Soubory
Před čtením této části doporučuji prostudovat ve skriptech kapitolu věnovanou souborům.
Uložení a obnovení stavu hry
Pro ukládání a načítání stavu hry je nejvhodnější použít serializaci objektů.
Serializace objektů
- serializace objektů umožňuje převést libovolný objekt (instanci) na posloupnost bajtů, kterou lze později načíst a původní objekt obnovit,
- serializace je nezávislá na platformě,
- užití:
- pro ukládání/obnovování stavu instancí,
- definování počátečního stavu instance v JavaBeanech,
- pro přenos pro síti - RMI
Třídy ObjectOutputStream a ObjectInputStream
- zapisování objektu do souboru (do výstupního streamu):
- zajišťuje třída ObjectOutputStream(OutputStream os) z java.io, která má metodu
void writeObject(Object o)
- omezení:
- ukládají se pouze objekty implementující rozhraní Serializable,
- ukládají se i všechny datové atributy v objektu (celou síť objektů),
- primitivní datové typy je potřeba zabalit do referenčních,
- čtení objektu ze streamu (ze souboru):
- třída ObjectInputStream(InputStream is) z java.io s metodou
- omezení:
- nutno zachovat pořadí objektů v jakém se ukládá,
- musí být k dispozici stejný soubor .class (stejné jméno a verze), který se použil při ukládání,
Rozhraní Serializable
- rozhraní Serializable je pouze příznak, nemá žádné metody,
- při implementaci rozhraní Serializable je nutné:
- všechny datové atributy musí být buď typu, který implementuje rozhraní Serializable, nebo to musí být primitivní datové typy (int, char, double, boolean, ...),
- předek by měl též implementovat rozhraní Serializable (neplatí pro třídu Object, neboť nemá datové atributy),
Uložení datových atributů do souboru
Následující kód by měl být v odpovídající metodě ve třídě Hra:
try {
// otevření soubor pro zápis instancí
// proměnná soubor buď obsahuje jméno souboru (tj. je typu String)
// nebo (lépe) je to instance třídy File
ObjectOutputStream vystup = new ObjectOutputStream(
new FileOutputStream(soubor));
// tímto příkazem se zapíše do souboru instance třídy herniPlan
// a všechny instance na které odkazuje - celý strom instancí
vystup.writeObject(herniPlan);
// zapisuji i seznam platných příkazů
vystup.writeObject(platnePrikazy);
vystup.close();
}
catch (FileNotFoundException e) {
System.out.println("Nepodarilo se otevrit vystupni soubor \""+soubor+"\"");
return;
}
catch (InvalidClassException e) {
System.out.println("Chyba ve tride urcene k serializaci");
return;
}
catch (NotSerializableException e) {
System.out.println("Nektere objekty nejsou serializovane");
return;
}
catch (IOException e) {
System.out.println("Chyba pri ukladani do souboru");
return;
}
Načtení datových atributů ze souboru:
Následující kód tvoří většinu odpovídající metody ve třídě Hra:
try {
// otevření souboru pro čtení
ObjectInputStream vstup = new ObjectInputStream(
new FileInputStream(soubor));
// načtení datových atributů, načítají se ve stejném pořadí, v jakém
// se zapisovaly,
herniPlan = (HerniPlan)vstup.readObject();
platnePrikazy = (SeznamPrikazu)vstup.readObject();
vstup.close();
}
catch (FileNotFoundException e) {
System.out.println("Nepodařilo se otevřít soubor s uloženými objekty");
return;
}
catch (StreamCorruptedException e) {
System.out.println("Chybná struktura souboru s objekty");
return;
}
catch (IOException e) {
System.out.println("Chyba při čtení ze souboru s uloženými objekty");
return;
}
catch (ClassNotFoundException e) {
System.out.println("V souboru nejsou uloženy instance příslušné třídy ");
return;
}
Postup vytvoření příkazů ulož a obnov
- vytipovat datové atributy ve třídě Hra, které udržují informace o stavu,
- projít typy (třídy) těchto atributů a zkontrolovat, zda jsou serializovatelné,
- pokud ne (např. třída Mistnost), zkontrolovat zda datové atributy v této třídě jsou serializovatelné, zda předek je serializovatelný – pokud ano, implementovat rozhraní Serializable,
- ve třídě Hra vytvořit metody pro uložení stavu hry a načtení stavu hry,
- vytvořit třídy PrikazUloz a PrikazObnov
Další možnosti serializace
- transient – modifikátor, který označuje dočasné datové atributy, které se nemají serializovat (ukládat, obnovovat),
- do třídy s implementovaným rozhraním Serializable můžete doplnit metody readObject a writeObject – tyto metody poté přebírají odpovědnost za ukládání/obnovu objektu při serializaci, použití:
- ukládání dodatečných informací,
- ke změně hodnot před uložením, ke změně hodnot či vyvolání metod po načtení,
- kontrola verze souboru .class:
- proměnná static final long serialVersionUID
- rozhraní Externalizable