【Java】クラスオブジェクトをセーブデータ化

2018年3月11日

本稿は自作クラスをそのままファイル化してしまう方法を紹介します。

クラスオブジェクトをセーブデータ化できるとプログラム側での利用が非常に楽になるというメリットがあります。

ただし、セーブされたクラスオブジェクトと復元対象のクラスの情報が違う場合にversionエラーが発生する可能性がある為、その辺を考慮したうえで使用する必要があります。

クラスオブジェクトをファイルに書き込み

クラスオブジェクトをファイル化するにはObjectOutputStreamを使用します。

writeObjectメソッドでオブジェクトデータを指定するだけで書き込みができます。

writeObjectメソッドに指定するオブジェクトはSerializableインターフェースを実装している必要があります。

クラス内に保持されているオブジェクトもそれぞれSerializableインターフェースを実装している必要があります。

試しにキャラクタのステータスをクラスごと書き込みしてみましょう。

  1. import java.io.BufferedOutputStream;
  2. import java.io.FileOutputStream;
  3. import java.io.IOException;
  4. import java.io.ObjectOutputStream;
  5. import java.io.Serializable;
  6.  
  7. public class Test {
  8. public static void main(String[] args) {
  9. try(FileOutputStream f = new FileOutputStream("status.dat");
  10. BufferedOutputStream b = new BufferedOutputStream(f);
  11. ObjectOutputStream out = new ObjectOutputStream(b)){
  12.  
  13. Status st = new Status("勇者", 100, 30);
  14.  
  15. out.writeObject(st);
  16. } catch ( IOException e ) {
  17. e.printStackTrace();
  18. }
  19. }
  20. }
  21. class Status implements Serializable{
  22. String name;
  23. int hp;
  24. int mp;
  25. Status(String name, int hp, int mp){
  26. this.name = name;
  27. this.hp = hp;
  28. this.mp = mp;
  29. }
  30. }
実行結果

status.datファイルが作成されました。

status.datファイルは「name=勇者,HP=100,MP=30」を保持するStatusオブジェクトのファイルということになります。

ObjectOutputStreamもいつも通りtry-with-resourceでcloseの自動呼出しの対象にしておきます。

クラスオブジェクトファイルの読み込み

保存したクラスオブジェクトファイルを読み込む場合はObjectInputStreamのreadObjectメソッドを利用します。

保存したクラスオブジェクトファイルを読み込んでステータスを表示してみます。

先ほど作成したstatus.datファイルを読み込んでみましょう。

  1. import java.io.BufferedInputStream;
  2. import java.io.FileInputStream;
  3. import java.io.IOException;
  4. import java.io.ObjectInputStream;
  5. import java.io.Serializable;
  6.  
  7. public class Test {
  8. public static void main(String[] args) {
  9. try(FileInputStream f = new FileInputStream("status.dat");
  10. BufferedInputStream b = new BufferedInputStream(f);
  11. ObjectInputStream in = new ObjectInputStream(b)){
  12.  
  13. Status st = (Status) in.readObject();
  14.  
  15. System.out.println(st.name);
  16. System.out.println(st.hp);
  17. System.out.println(st.mp);
  18. } catch ( IOException e ) {
  19. e.printStackTrace();
  20. } catch (ClassNotFoundException e) {
  21. e.printStackTrace();
  22. }
  23. }
  24. }
  25. class Status implements Serializable{
  26. String name;
  27. int hp;
  28. int mp;
  29. Status(String name, int hp, int mp){
  30. this.name = name;
  31. this.hp = hp;
  32. this.mp = mp;
  33. }
  34. }
実行結果

勇者
100
30

ちゃんと保存した内容が復元されていますね。

こちらもcloseメソッドはしっかり呼び出されるようにしておいてください。

transient修飾子

transient修飾子を利用すると、変数を保存対象から除外することができます。

まあ使いどころは、ほぼないのですが一応紹介しておきましょう。

Statusクラスのhpとmpの変数にtransient修飾子を付与してみました。

  1. import java.io.BufferedOutputStream;
  2. import java.io.FileOutputStream;
  3. import java.io.IOException;
  4. import java.io.ObjectOutputStream;
  5. import java.io.Serializable;
  6.  
  7. public class Test {
  8. public static void main(String[] args) {
  9. try(FileOutputStream f = new FileOutputStream("status.dat");
  10. BufferedOutputStream b = new BufferedOutputStream(f);
  11. ObjectOutputStream out = new ObjectOutputStream(b)){
  12.  
  13. Status st = new Status("勇者", 100, 30);
  14.  
  15. out.writeObject(st);
  16. } catch ( IOException e ) {
  17. e.printStackTrace();
  18. }
  19. }
  20. }
  21. class Status implements Serializable{
  22. String name;
  23. transient int hp;
  24. transient int mp;
  25. Status(String name, int hp, int mp){
  26. this.name = name;
  27. this.hp = hp;
  28. this.mp = mp;
  29. }
  30. }
  1. import java.io.BufferedInputStream;
  2. import java.io.FileInputStream;
  3. import java.io.IOException;
  4. import java.io.ObjectInputStream;
  5. import java.io.Serializable;
  6.  
  7. public class Test {
  8. public static void main(String[] args) {
  9. try(FileInputStream f = new FileInputStream("status.dat");
  10. BufferedInputStream b = new BufferedInputStream(f);
  11. ObjectInputStream in = new ObjectInputStream(b)){
  12.  
  13. Status st = (Status) in.readObject();
  14.  
  15. System.out.println(st.name);
  16. System.out.println(st.hp);
  17. System.out.println(st.mp);
  18. } catch ( IOException e ) {
  19. e.printStackTrace();
  20. } catch (ClassNotFoundException e) {
  21. e.printStackTrace();
  22. }
  23. }
  24. }
  25. class Status implements Serializable{
  26. String name;
  27. transient int hp;
  28. transient int mp;
  29. Status(String name, int hp, int mp){
  30. this.name = name;
  31. this.hp = hp;
  32. this.mp = mp;
  33. }
  34. }
実行結果

勇者
0
0

hp=100、mp=30で保存しましたが読み込んだときに値が0となりました。これはクラスの初期化時に0が代入されるからです。

これでhpとmpは保存されなかったのがわかると思います。

Java

Posted by nompor