# Properties file ändern



## JavaGamer (31. Dez 2015)

Hi,

ich habe folgendes Problem:
Also ich habe ein paar Methoden geschrieben zum einlesen und schreiben einer Propeties Datei, nun möchte ich aber, dass wenn z.B. ein boolean Wert im Programm auf false gesetzt wird dies in der Propeties-Datei gespeichert wird, bisher hat es bei mir aber nicht so geklappt wie geplant:


```
public static void setProperty(String key, String value, File file) {
        try (OutputStream output = new FileOutputStream(file)) {
            Properties prop = read(file);
            prop.put(key, value);
          
            prop.store(output, "v1.1.0");
        } catch (IOException e) {
            SilenceException.reThrow(e);
        }
    }

    public static Properties read(File file) {
        Properties prop = new Properties();
      
        try (InputStream input = new FileInputStream(file)) {
            // load a properties file
            prop.load(input);
          
            return prop;
        } catch (IOException e) {
            SilenceException.reThrow(e);
        }
        return null;
    }
```

Hier der Code der diese Methode aufruft um Änderungen zu speichern:

```
private static void writeOptions() {
        PropertyUtil.setProperty("animations", "" +  OptionsState.animations, properties);
        PropertyUtil.setProperty("logo", "" + OptionsState.logos, properties);
        PropertyUtil.setProperty("fullscreen", "" + OptionsState.fullscreens, properties);
        PropertyUtil.setProperty("music", "" + OptionsState.music, properties);
        PropertyUtil.setProperty("explosion", "" + OptionsState.explosion, properties);
        PropertyUtil.setProperty("shot", "" + OptionsState.shot, properties);
        PropertyUtil.setProperty("button", "" + OptionsState.button, properties);
        PropertyUtil.setProperty("highscore", "" + OptionsState.HIGHSCORE, properties);
        PropertyUtil.setProperty("live", "" + OptionsState.LIVE, properties);
        PropertyUtil.setProperty("speed", "" + OptionsState.SPEED, properties);
        PropertyUtil.setProperty("build", "" + Dejustice.build, properties);
    }
```

Hier noch mal eben der Code zu properties:

```
private static File properties;
[...]
    public static void init() {
        properties = new File("options.properties");
```

Um genau zu sein, das Problem besteht darin, dass nur die letze Zeile gespeichert wird und bei meinen anderen Versuchen wurde immer nur die ganze Datei kopiert und wieder eingefügt und dann die Änderung darunter eingefügt, anstatt einfach den Wert der bereits vorhandenen property auszutauschen.
Ich hoffe ihr könnt mir helfen! *Genutzt wird übrigens Java 8 und ich möchte eigentlich sämtlichen Code vermeiden der sich durch Java 8 anders lösen lässt!*
Sollte es euch wundern, woher die Klasse SilenceException kommt, dies ist einfach ein Bestandteil einer Engine die ich verwende und sorgt einfach nur dafür, dass die Exception in einen log geschrieben wird, sollte eine Exception enstehen. 

JavaGamer


----------



## knilch (31. Dez 2015)

Hi,
Das mit den Properties ist ganz einfach.
Properties kannst du so ansehen wie eine Map<key,value>. Der Key ist dabei der Name vom Property und Value der Wert von diesem Property.
Bei dir wären die keys: animations, logo, fullscreen, music, explosion, shot, button, highscore, live, speed, build; und die values dazu die Werte von: animations, logo, fullscreen, music, explosion, shot, button, highscore, live, speed, build.
Hier mal ein kleines Beispiel wie das so mit den Properties geht:
Im Start liest du die Properties von der Datei ein. Dann verwendest du die Properties, änderst sie und beendest dann das Programm. Dabei werden die Properties in die Datei gespeichert.

```
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Map.Entry;
import java.util.Properties;

public class PropertyTest {
    private static Properties properties;

    public static void main(String[] args) {
        File propertyFile = new File("res/conf.properties");
        loadProperties(propertyFile);
        showProperties();
        changeProperty("animations", false);
        showProperties();
        saveProperties(propertyFile);
    }

    private static void loadProperties(File propertyFile) {
        FileInputStream propInFile;
        try {
            propInFile = new FileInputStream(propertyFile);
            properties = new Properties();
            properties.load(propInFile);
        }
        catch(IOException e) {
            System.err.println(e.getMessage());
        }
    }

    private static void saveProperties(File propertyFile) {
        FileOutputStream propOutFile;
        try {
            propOutFile = new FileOutputStream(propertyFile);
            properties.store(propOutFile, "");
        }
        catch(IOException e) {
            System.err.println(e.getMessage());
        }

    }

    private static void showProperties() {
        for(Entry<Object, Object> entry : properties.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
    }

    private static void changeProperty(String key, Object value) {
        if(properties.containsKey(key))
            properties.remove(key);
        if(value instanceof String )
            properties.put(key, value);
        else
            properties.put(key, "" + value);
    }
}
```
conf.properties

```
#
#Thu Dec 31 08:03:44 CET 2015
highscore=255
music=false
live=3
speed=20
logo=\\path\\to\\file
button=11
fullscreen=true
build=4
explosion=false
animations=true
shot=1
```
Und noch etwas...
Wenn du auf die boolean oder int-Values zugreifen möchtest, diese werden als String zurückgegeben...
also muss du evtl. den String parsen mit :
Integer.parseInt((String)entry.getValue()) 
oder 
Boolean.parseBoolean( (String) entry.getValue());


----------



## JavaGamer (31. Dez 2015)

Ok, damit funktioniert es nun, auch wenn ich den try-catch Block ein wenig angepasst habe.
Nur die Performance ist nicht so gut, mal schauen obs an der Propety oder am Enum liegt.


----------



## Flown (31. Dez 2015)

Was heißt die Performance ist nicht so gut?


----------



## JavaGamer (31. Dez 2015)

Nun ja, ich habe im Endeffekt den Property Code eingefügt und die normalen Einstellungswerte (boolean, ints etc.) in ein enum gestopft --> Resultat: manchmal nimmt der Button keine Knopfdrücke mehr an

Desweiteren springt dieser nicht sofort von On auf Off, sondern der Text wird mehr oder weniger in Zeitlupe gerendert, zumindest kommt einem der Wechsel von On nach Off und umgekehrt im Vergleich zu vorher wie in Zeitlupe vor.

CPU Auslastung ist bei 4%, gerendert wird über die GPU (NVIDIA 960 OC) mit OpenGL 3.3.
Wieso dies jetzt so aufeinmal so langsam läuft habe ich übrigens bisher noch nicht herausgefunden, ich weiß auch nicht wirklich wie man soetwas herausfindet, rate mich da eher durch.
Der Code:

```
public enum Option {
     ANIMATIONS("true"),
     LOGO("true"),
     FULLSCREEN("true"),
     MUSIC("true"),
     SNDEXPLOSION("true"),
     SNDSHOT("true"),
     SNDBUTTON("true"),
     HIGHSCORE("0"),
     LIVE("5"),
     SPEED("4");
    
     private String string;
    
     Option(String value) {
       this.string = value;
     }
    
     public void setValue(String value) { this.string = value; }
     public void setObject(Object value) { this.string = String.valueOf(value); }
     public void setBool(boolean value) { this.string = "" + value; }
     public void setLong(long value) { this.string = String.valueOf(value); }
     public void setInt(int value) { this.string = String.valueOf(value); }
     public void setFloat(float value) { this.string = String.valueOf(value); }
     public void setDouble(double value) { this.string = String.valueOf(value); }
    
     public String getValue() { return string; }
     public boolean getBool() { return string.equals("true") ? true : false; }
     public long getLong() { return Long.parseLong(string); }
     public int getInt() { return Integer.parseInt(string); }
     public float getFloat() { return Float.parseFloat(string); }
     public double getDouble() { return Double.parseDouble(string); }
   }

  public static void change(Option option, String key, Object value) {
     System.out.println(option.toString()); // wird anscheinend 5 mal ausgegeben bei einem Knopfdruck
     option.setValue("" + value);
     property.change(key, value);
   }
  public static void dispose() {
     property.save(properties);
   }
```

Dieser Code wird ausgeführt wenn der Button "animation" gedrückt wird:
update-Part:

```
if(animation.check(Mouse.MOUSE_BUTTON_LEFT))
       Option.ANIMATIONS.setBool(!Option.ANIMATIONS.getBool());
```
render-Part:

```
animation.render(g2d, Color.DARK_GRAY, "Animations " +(Option.ANIMATIONS.getBool() ? "ON" : "OFF"));
```

Ich hoffe dies hilft weiter.
JavaGamer

EDIT: Achja, der code für die property:

```
public void change(String key, Object value) {
        if(properties.containsKey(key))
            properties.remove(key);
        if(value instanceof String)
            properties.put(key, value);
        else
            properties.put(key, "" + value);
    }
```


----------



## Flown (31. Dez 2015)

Mit `properties::setProperty` wärst du besser bedient als mit deinem `change(String, Object)`.
Optionen mit einem Enum zu lösen sieht merkwürdig aus, aber ok man kanns so machen (Sieh dir besser mal die RenderingHints an, wie die das gelöst haben). Im Enum selbst nimm keinen String sondern Object und parse die Daten nur einmal beim laden!


----------



## JavaGamer (31. Dez 2015)

Ok, nur wie und wo im Code soll ich das mit "properties::setProperty" umsetzten? Und was mir diese RenderingHints bringen solln verstehe ich auch noch nicht so wirklich.
Also eingelesen wird die Datei nur einmal beim starten der Anwendung und dann in die Variablen eingespeichert. Desweiteren, wenn ich das als Object einspeichere, wie komme von einem Objekt zu einem Boolean oder einem Integer etc., da z.B. bisher im Menü selbst fast alles mit boolean abfragen gemacht wird (darum getBool() als getter). Und den String hatte ich genommen, damit ich nicht für alles eine einzelne Variable erstellen muss, da vom String kommt ja so ziehmlich überall in oder vlt. sogar überall hin. Nun ja, dass mit dem Enum war nur eine Idee, da mir irgendwie das alte System nicht mehr gefiel wo da mal ein boolean war, da mal ein Integer etc.

Und mal abseits dieses Problems, wie machst du diese grauen Makierungen mitten im Text? xD


----------



## Flown (31. Dez 2015)

```
public void change(String key, Object value) {
   if(properties.containsKey(key))
      properties.remove(key);
   if(value instanceof String)
      properties.put(key, value);
   else
      properties.put(key, "" + value);
}
```
ist gleich wie:

```
properties.setProperty(key, value);
```

Enums sind Konstanten und Konstanten per Definition bieten einen Fakt! Das heißt RenderingHints z.B. haben für Aliasing einen Aliasing_Key und Aliasing_Value_On (resp. Off). Das sind wirklich Konstanten. Deine "Konstanten" hingegen sind aber veränderlich und führen einen internen State (kann man machen, da du da Key und Value in einem vereinst).

PS: Die grauen Stellen sind [icode][/icode] Tags und stellen einen Inlinecode dar!


----------



## JavaGamer (31. Dez 2015)

Nun ja, das mit den Enums war ja nur meine Idee, da ich es einfach nicht mehr so schön fand mal da ein int zu haben, da ein boolean etc. und die Enums sind dat einzige was mir da so eingefallen ist, zumal der Code vorher überall durcheinander war und jetzt schön zentral geordnet ist. (lag wohl vorher auch daran, dass ich wenn ich was ausprobiere nie wirklich OOP anwende, da dies dann immer zum fail führt und ich dat iwi immer nur im späteren cleanup wenn ich weiß wie's geht schön hinbekomme ohne Probleme)

Also kann ich einfach z.B. `properties::setProperty` schreiben anstatt `properties.setProperty(key, value);`, zumindest in der Theorie, wenn ichs richtig verstanden habe, da in der Praxis führt dies zum Error. Habe leider auch kaum einen Plan von Lambda-Ausdrücken, muss diese immer nachgooglen wenn ich einen verwenden will und bis auf das neue Filesystem und diese try-catch Blöcke mit Klammern, die glaub ich auch von Java 8 stammen bin ich fast komplett auf Java 7 stehen geblieben iwi, da ich damals mich von Java mehr abgewendet hatte (und wohl auch zu faul war/bin um Bücher durchzulesen oder tuts anschauen, da diese meist weniger Wissen vermitteln als Bücher, learning by trying  )..... Desweiteren müsste die Methode `change` wohl bleiben, da sich diese in der Klasse `PropertyList` befindet und für die Optionen von der Klasse `Options` aufgerufen wird. (Option ist eine Enum-Klasse in der Klasse Options).

Und meiner Meinung nach ist es auch ein Fakt wenn Enumwert ANIMATIONS mit der Methode getBool true zurückgibt, da true eine tatsache in dem Fall ist. 
Im Enum habe ich übrigens extra einen String genommen, da ich weiß wie ich vom String zum boolean komme, aber nicht wie ich vom Object zum boolean komme (was übrigens meine erste Idee war, bevor ich auf String gekommen bin). Da irgendwoher muss ja mein Menü mit boolean-Werten, Integer-Werten etc. gefüttert werden. Ein Enum hatte ich übrigens genommen, da z.B. bei Game States dieser auch gerne benutzt wird, von dem was ich so gesehen habe.

Die gesammte Property-Datei wird doch auch nur einmal eingelesen, in der init() Methode beim starten vom Game und nur einmal gespeichert, in der dispose() Methode, wenn das Game beendet wird.
Mal so nebenbei, wie macht man das eigentlich als Profi-Java Entwickler mit OOP und wenn man etwas ausprobiert, ständig neue Dinge einfügt etc. ... endet bei mir nähmlich immer in Frustration und Chaos im Code nach so ca. 10 Versionen eines Projektes, dass ich meist wenn ich Lust habe wieder bei 0 Anfangen muss um sauberen Code als Ergebnis zu erhalten.


----------



## knilch (31. Dez 2015)

> Also kann ich einfach z.B. properties::setProperty schreiben anstatt properties.setProperty(key, value);, zumindest in der Theorie, wenn ichs richtig verstanden habe, da in der Praxis führt dies zum Error.


properties.setProperty(key, value) ist die Variante, um die Properties zu ändern.
properties::setProperty ist pseudo-code.


> Habe leider auch kaum einen Plan von Lambda-Ausdrücken, muss diese immer nachgooglen wenn ich einen verwenden will und bis auf das neue Filesystem und diese try-catch Blöcke mit Klammern, die glaub ich auch von Java 8 stammen bin ich fast komplett auf Java 7 stehen geblieben iwi, da ich damals mich von Java mehr abgewendet hatte (und wohl auch zu faul war/bin um Bücher durchzulesen oder tuts anschauen, da diese meist weniger Wissen vermitteln als Bücher, learning by trying  ).....


Tipp: mach einen update der jdk auf Java 8. und setzte dich mit Lambda-Expressions auseinander. Sind für collections, filters etc. sehr hilfreich..
(und falls du JavaFX noch nicht kennst, arbeite dich mal in diese Thematik ein! Ist aber auch in jdk 7 vorhanden...)
Auch Properties vom JavaFx-Package sind sehr sehr interessant, da mit diesen bindings gemacht werden können. Diese sind ideal wenn in einem GUI bei laufender Verarbeitung updates gemacht werden..


> Desweiteren müsste die Methode change wohl bleiben, da sich diese in der Klasse PropertyList befindet und für die Optionen von der Klasse Options aufgerufen wird. (Option ist eine Enum-Klasse in der Klasse Options).
> 
> Und meiner Meinung nach ist es auch ein Fakt wenn Enumwert ANIMATIONS mit der Methode getBool true zurückgibt, da true eine tatsache in dem Fall ist.
> Im Enum habe ich übrigens extra einen String genommen, da ich weiß wie ich vom String zum boolean komme, aber nicht wie ich vom Object zum boolean komme (was übrigens meine erste Idee war, bevor ich auf String gekommen bin). Da irgendwoher muss ja mein Menü mit boolean-Werten, Integer-Werten etc. gefüttert werden. Ein Enum hatte ich übrigens genommen, da z.B. bei Game States dieser auch gerne benutzt wird, von dem was ich so gesehen habe.
> ...


Beim Entwickeln passiert es vielfach, dass man Teile von einer Methode ersetzten, umbschreiben muss. Dabei ist es eine Variante, die aktuell funktionierende Methode so zu lassen und eine neue Methode zu erstellen, die dann das gewünschte Verhalten ausführt.
Wenn dann mit der neuen Methode alles korrekt funktioniert, kann die alte Methode gelöscht werden. Dabei helfen Unit-Tests, mit denen das Verhalten von Methoden überprüft werden kann..
Hilfreich ist auch der Einsatz von einer Vesion Controll Software wie git, svn etc. Solche Systeme erleichtern das Verwalten von Projekten während den verschiedenen Entwicklungszyklen.


----------



## JavaGamer (31. Dez 2015)

Was ist eigentlich pseudo-code, der Name kommt mir bekanntvor, aber mir will dazu gerade nichts einfallen. 
Java JDK 8: das letzte Update installiert.  Habe eigentlich immer die aktuellste Javaversion des JDKs und JREs installiert, nur bin halt recht faul wenns ums lernen geht und darum kenne ich viele Dinge von Java 8 nicht zu 100% oder nicht auswenig, was eigentlich von dem was ich so im Internet in Foren gesehen habe nur die Lamda-Ausdrücke sein sollten..., was wiederrum bedeutet, dass ich nur ein paar vordefinierte kenne...ach und die Java 8 funktionalen Interfaces, wobei ich sowieso mich noch nie mit Interfaces auseinandergesetzt habe.... Desweiteren, mit JavaFX habe ich schon mal ein wenig gearbeitet vor längerer Zeit, allerdings wird mir dies in diesem Fall nicht weiterhelfen, da ich an einem kleinen Computerspiel arbeite, welches auf der SilenceEngine basiert (mehr ein Framework welches auf LWJGL 3 mit OpenGL 3.3 und OpenAL 1 oder 1.1 basiert). Dementsprechend habe ich keine Bestandteile von Swing, AWT oder JavaFX im Code und die update und render Methoden die jeweils meinen Code aufrufen sind alles Teile der Engine/des Frameworks, welches diese je nach GameState aufruft (60mal die Sekunde die update Methode, render Methode so oft wie möglich soweit ich weiß).

Was sind eigentlich Unit-Tests? Tools wie git etc. kenne ich, verwende ich für viele meiner Projekte sogar, aber nicht für alle aus irgendeinem Grund.


----------



## knilch (1. Jan 2016)

> Was ist eigentlich pseudo-code, der Name kommt mir bekanntvor, aber mir will dazu gerade nichts einfallen



Pseudocode ist ein Programmcode, der nicht zur maschinellen Interpretation, sondern lediglich zur Veranschaulichung eines Paradigmas oder Algorithmus dient. https://de.wikipedia.org/wiki/Pseudocode


> nur bin halt recht faul wenns ums lernen geht und darum kenne ich viele Dinge von Java 8 nicht zu 100% oder nicht auswenig


Nun da kann ich nix dazu sagen, aber wenn du in Java (oder auch einer anderen Sprache) programmieren willst, dann wirst du dich mit Büchern, Tutorials und API-Docs auseinandersetzten...Du musst nicht immer alles auswendig wissen. Wichtig ist, das du weisst, wo du nachschauen musst, wie etwas funktioniert. Das bedingt, dass du dich mit API-Docs auseinander setzt.


> ...gesehen habe nur die Lamda-Ausdrücke sein sollten...


Da ist noch etwas mehr als Lambda Expressions dazu gekommen... http://www.oracle.com/technetwork/java/javase/8-whats-new-2157071.html


> Was sind eigentlich Unit-Tests?


Unit-Tests: https://de.wikipedia.org/wiki/JUnit


----------



## JavaGamer (2. Jan 2016)

Ok, Problem behoben und gefunden. Da hatte sich wohl ein Tippfehler bei einer Variable eingeschlichen ohne dass ich dies gemerkt habe, als ich den Wert geändert habe. xD
Läuft jetzt einwandfrei und danke für die Hilfe.


----------

