java.util.Properties
Klasse, mit der Eigenschaften gelesen und geschrieben werden können. Aussehen könnte das ganze wie folgt:/** * Lese properties file. */ public void readProperties() { Properties properties = new Properties(); try { properties.load(new FileInputStream("filename.properties")); } catch (IOException e) { e.printStackTrace(); } } /** * Schreibe properties file. */ public void writeProperties(Properties properties) { try { properties.store(new FileOutputStream("filename.properties"), null); } catch (IOException e) { e.printStackTrace(); } }
Der Zugriff erfolgt dann, gleich einer HashMap, via
props.getProperty("key")
. Das ist alles sehr einfach und reicht oftmals aus, um ein paar Werte zur Laufzeit wegzuschreiben. Will man aber Arrays, Objekte oder ganze Wertebeziehungen speichern, muss man diese zunächst in einen String codieren bzw. beim Lesen wieder decodieren. Ist man im Begriff mit so etwas zu beginnen, empfiehlt es sich gleich etwas anderes zu verwenden, weil hier die Rattenschwanzgefahr recht groß ist und letztendlich nur vom Projektziel ablenkt. Gesehen habe ich das allerdings schon mehrfach. Dabei bringt Java für anspruchsvollere Anwendungseigenschaften noch etwas anderes, besseres mit.Im Package
java.util.prefs
gibt es die Klasse Preferences
, die eine hierarchische Werte- und Objektablage bietet. So ist mittels Preferences.userRoot()
eine Rootknoten erhältlich, in den wir bereits verschiedene Objekte ablegen können. Besser ist es aber, einen eigenen Knoten für die Anwendung bereitzustellen, um nicht mit anderen Anwendungen zu kollidieren. Preferences werden nämlich im Benutzerverzeichnis für alle Anwendungen unter .userPrefs/prefs.xml abgelegt. Via Preferences.systemRoot()
lassen sich auch systemweite Einstellungen speichern. Um die Anwendungseinstellungen zu laden empfiehlt es sich, einen Unterknoten zu verwenden, der wie folgt erzeugt/geladen werden kann: Preferences.userRoot().node("TestApp")
. Dieser Knoten kann nun als Basis für weitere Unterknoten oder für die Werteablage dienen. Um das Laden und Speichern müssen wir uns bequemer Weise nicht kümmern. Unser Knoten befindet sich nach dem Neustarten der Anwendung im gleichen Zustand. Der Zugriff auf die Knoteneigenschaften erfolgt mittels put
- und get
-Methoden.java.util.prefs.Preferences appNode = Preferences.userRoot().node("TestApp"); appNode.putInt("fontsize", 10); //Eigenschaft setzen int fontsize = appNode.getInt("fontsize", 10); //Eigenschaft lesen
Das ganze kann noch weiter getrieben werden, so dass zum Beispiel für jedes Paket ein neuer Knoten verwendet wird.
Preferences packageNode = appNode.node(Test.class.getName())
Bis jetzt lassen sich aber nur die gängigen Wrapper-Klassen sowie Strings und Bytearrays ablegen. Um (fast) beliebige Objekte abzulegen, lässt sich die Serialisierbarkeit von Objektinstanzen nutzen. Die zugrundeliegende Klasse muss also das Serializable-Interface implementieren. Die der Klasse zugrunde liegenden Objektinstanzen können anschließend in ein Bytearray umgewandelt werden, das wiederum mit der Methode
putByteArray
in den Preferences-Knoten gespeichert werden kann./** * Objektinstanzen serialisieren. */ static private byte[] object2Bytes(Object o) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(o); return baos.toByteArray(); }
Der Rückweg, aus dem Bytearray eine Objektinstanz zu erzeugen, ist ebenso einfach.
/** * Serialisierte Objektinstanz wiederherstellen */ static private Object bytes2Object(byte raw[]) throws IOException, ClassNotFoundException { ByteArrayInputStream bais = new ByteArrayInputStream(raw); ObjectInputStream ois = new ObjectInputStream(bais); Object o = ois.readObject(); return o; }
Bei der Objektserialisierung ist immer darauf zu achten, dass die Member-Variablen der zugrundeliegenden Klasse wiederum serialisierbare Klassen referenzieren. Andernfalls sind die Member-Variablen mit
transient
zu kennzeichnen. Das Gilt zum Beispiel für Streams, die nicht einfach serialisiert werden können. Bei der Wiederherstellung enthalten diese Member-Variablen den Wert null
.Die Datenablage erfolgt - wie nicht anders zu erwarten - im XML-Format. Das Endergebnis können wir uns auch ausgeben lassen.
public static void printPreferences(Preferences prefs) throws IOException, BackingStoreException { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); prefs.exportNode(byteArrayOutputStream); System.out.println(new String(byteArrayOutputStream.toByteArray())); }
Und die Ausgabe.
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd"> <preferences EXTERNAL_XML_VERSION="1.0"> <root type="user"> <map/> <node name="TestApp"> <map> <entry key="fontsize" value="10"/> </map> </node> </root> </preferences>
Links: IBM Developerworks
Keine Kommentare:
Kommentar veröffentlichen
Hinweis: Nur ein Mitglied dieses Blogs kann Kommentare posten.