0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

オブジェクト指向って何?RPGで理解する超入門 Part2 (ファイル入出力)

0
Last updated at Posted at 2026-01-02

part2_episode01_title_banner.png

Java Quest Part 2: 実用機能マスター編
難易度: ★★★☆☆ (3/5)
学習時間: 約35分

この回で学ぶこと

Part 1で作ったRPGシステムは動作していますが、ゲームを終了するとデータが消えてしまいます

今回はファイル入出力を学んで、キャラクターデータを保存(セーブ) して
読み込む(ロード) 機能を実装しましょう!

学習内容

  • ファイル入出力の基本概念
  • FileWriterFileReader の使い方
  • try-with-resources 構文
  • セーブ・ロード機能の実装

今回の成果物

// セーブ機能
SaveManager.save(player, "save_data.txt");

// ロード機能
Player player = SaveManager.load("save_data.txt");

📁 プロジェクト構成

この回で作成するセーブ・ロードシステムのファイル構成

save_load_system/
├── src/
│   ├── com/javaquest/
│   │   ├── model/
│   │   │   └── Player.java         # プレイヤークラス
│   │   └── manager/
│   │       └── SaveManager.java    # セーブ・ロード管理
│   └── practice/
│       ├── NameSaver.java          # 練習1:名前だけ保存
│       └── StatusSaver.java        # 練習2:ステータス保存
├── data/                           # セーブデータ保存先
│   ├── player_name.txt             # プレイヤー名
│   └── status.txt                  # ステータスデータ
└── README.md                       

パッケージ構成の意味:

  • com.javaquest.model → データクラス(Player等)
  • com.javaquest.manager → 管理クラス(SaveManager等)
  • com.javaquest → メインシステム
  • practice → 練習問題用ファイル
  • data/ → セーブデータ保存先

📚GitHub:成果物のサンプルはこちら

なぜファイル入出力が必要?

問題点: データが消える!

public class Main {
    public static void main(String[] args) {
        Player player = new Player("勇者", 100, 50);
        player.levelUp();
        System.out.println(player.getName() + " レベル:" + player.getLevel());
        // ここでプログラム終了 → データが消える!
    }
}

プログラムを終了すると、メモリ上のデータはすべて消えてしまいます

解決策: ファイルに保存!

データをファイルに保存すれば、プログラムを終了してもデータが残ります

データ永続化の仕組み

基礎知識

1. ファイル入出力とは?

ファイル入出力(File I/O) とは、プログラムとファイルの間でデータをやり取りすることです。

ファイル入出力の仕組み.png

用語 意味
入力(Input) ファイルからデータを読み込む ロード機能
出力(Output) ファイルにデータを書き込む セーブ機能

2. Java でのファイル操作

Java には複数の方法がありますが、今回は最も基本的な方法を使います。

ファイルに書き込む: FileWriter

WriteExample.java
import java.io.FileWriter;
import java.io.IOException;

public class WriteExample {
    public static void main(String[] args) {
        try {
            FileWriter writer = new FileWriter("C:\\work\\java-quest\\test.txt");
            writer.write("Hello, World!");
            writer.close();  // 重要: 必ず閉じる!
            System.out.println("ファイルに書き込みました!");
        } catch (IOException e) {
            System.out.println("エラーが発生しました: " + e.getMessage());
        }
    }
}

実行結果:
C:\work\java-questフォルダにtest.txt というファイルが作成され、"Hello, World!" が保存されます。
画像1.png

ファイルから読み込む: FileReader + BufferedReader

import java.io.FileReader;
import java.io.BufferedReader;
import java.io.IOException;

public class ReadExample {
    public static void main(String[] args) {
        try {
            FileReader reader = new FileReader("C:\\work\\java-quest\\test.txt");
            BufferedReader br = new BufferedReader(reader);
            
            String line = br.readLine();  // 1行読み込み
            System.out.println("読み込んだ内容: " + line);
            
            br.close();
            reader.close();
        } catch (IOException e) {
            System.out.println("エラーが発生しました: " + e.getMessage());
        }
    }
}

実行結果:

読み込んだ内容: Hello, World!

3. try-with-resources 構文

close() を書き忘れるとメモリリークが発生します。
try-with-resources を使うと、自動で閉じてくれます

try_with_resources_comparison.png

従来の方法(closeを忘れるリスク)

FileWriter writer = new FileWriter("test.txt");
try {
    writer.write("Hello!");
} finally {
    writer.close();  // 忘れやすい!
}

try-with-resources(推奨)

try (FileWriter writer = new FileWriter("test.txt")) {
    writer.write("Hello!");
    // 自動で close() される!
} catch (IOException e) {
    e.printStackTrace();
}

Java 7以降はこちらを使いましょう!

4. よくある間違い

間違い1: close() を忘れる

FileWriter writer = new FileWriter("test.txt");
writer.write("データ");
// close() を忘れた! → ファイルが壊れる可能性

正解: try-with-resources

try (FileWriter writer = new FileWriter("test.txt")) {
    writer.write("データ");
}  // 自動で close()

間違い2: 例外処理を書かない

// コンパイルエラー!
FileWriter writer = new FileWriter("test.txt");

理由: FileWriterIOException をスローする可能性があるため、try-catch が必須

正解: try-catch で囲む

try (FileWriter writer = new FileWriter("test.txt")) {
    writer.write("データ");
} catch (IOException e) {
    System.out.println("エラー: " + e.getMessage());
}

実装演習: セーブ・ロード機能を作ろう!

それでは、RPGキャラクターのデータを保存・読み込みする機能を実装しましょう!

ステップ1: Player クラスの準備

まずは、Part 1 で作った Player クラスを用意します。

Player.java
/**
 * ゲームのプレイヤーを表すクラスです。
 * プレイヤーの名前、HP(体力)、レベルなどの情報を管理します。
 * 
 * 使い方の例:
 * Player player = new Player("勇者", 100, 1);
 * player.displayStatus(); // プレイヤーの情報を表示
 * 
 */
public class Player {
    /** プレイヤーの名前(例:"勇者"、"魔法使い"など) */
    private String name;
    
    /** 現在のHP(体力)。0になると倒れてしまいます */
    private int hp;
    
    /** 最大HP(体力の上限)。回復するときの目安になります */
    private int maxHp;
    
    /** プレイヤーのレベル。強さを表します */
    private int level;
    
    /**
     * 新しいプレイヤーを作成します。
     * 作成時は体力が満タンの状態でスタートします。
     * 
     * @param name プレイヤーの名前(例:"勇者")
     * @param maxHp 最大HP(体力の上限、例:100)
     * @param level プレイヤーのレベル(例:1)
     */
    public Player(String name, int maxHp, int level) {
        this.name = name;
        this.maxHp = maxHp;
        this.hp = maxHp;  // 最初は体力満タン
        this.level = level;
    }
    
    /**
     * プレイヤーの名前を取得します。
     * @return プレイヤーの名前
     */
    public String getName() { return name; }
    
    /**
     * 現在のHPを取得します。
     * @return 現在のHP(0以上の数値)
     */
    public int getHp() { return hp; }
    
    /**
     * 最大HPを取得します。
     * @return 最大HP(体力の上限値)
     */
    public int getMaxHp() { return maxHp; }
    
    /**
     * プレイヤーのレベルを取得します。
     * @return 現在のレベル
     */
    public int getLevel() { return level; }
    
    /**
     * プレイヤーのHPを設定します。
     * ダメージを受けたり、回復したりするときに使います。
     * 
     * 注意:HPは0未満にならないように、また最大HPを超えないように
     * 呼び出し側で調整してください。
     * 
     * @param hp 設定したいHP(0以上、maxHp以下が推奨)
     */
    public void setHp(int hp) { this.hp = hp; }
    
    /**
     * プレイヤーの現在の状態を画面に表示します。
     * 名前、HP、レベルを見やすい形で出力します。
     * 
     * 表示例:
     * ========== ステータス ==========
     * 名前: 勇者
     * HP: 80/100
     * レベル: 5
     * ===============================
     */
    public void displayStatus() {
        System.out.println("========== ステータス ==========");
        System.out.println("名前: " + name);
        System.out.println("HP: " + hp + "/" + maxHp);
        System.out.println("レベル: " + level);
        System.out.println("===============================");
    }
}

ステップ2: SaveManager クラスの作成

セーブ・ロード機能を管理するクラスを作ります。

SaveManager.ja
import java.io.*;

/**
 * ゲームのセーブ・ロード機能を管理するクラスです。
 * プレイヤーのデータをファイルに保存したり、ファイルから読み込んだりできます。
 * 
 * 使い方の例:
 * // セーブする場合
 * Player player = new Player("勇者", 100, 5);
 * SaveManager.save(player, "save_data.txt");
 * 
 * // ロードする場合
 * Player loadedPlayer = SaveManager.load("save_data.txt");
 * 
 */
public class SaveManager {
    /**
     * プレイヤーのデータをテキストファイルに保存します。
     * 名前、現在のHP、最大HP、レベルの順番で1行ずつ保存されます。
     * 
     * 保存されるファイルの中身の例:
     * 勇者
     * 80
     * 100
     * 5
     * 
     * @param player 保存したいプレイヤーオブジェクト
     * @param filename 保存先のファイル名(例:"save_data.txt")
     */
    public static void save(Player player, String filename) {
    	
        try (FileWriter writer = new FileWriter(filename)) {
            // プレイヤーのデータを1行ずつファイルに書き込み
            writer.write(player.getName() + "\n");      // 名前
            writer.write(player.getHp() + "\n");        // 現在のHP
            writer.write(player.getMaxHp() + "\n");     // 最大HP
            writer.write(player.getLevel() + "\n");     // レベル
            
            System.out.println("セーブ完了: " + filename);
            
        } catch (IOException e) {
            System.out.println("セーブ失敗: " + e.getMessage());
        }
    }
    
    /**
     * テキストファイルからプレイヤーのデータを読み込んで、Playerオブジェクトを作成します。
     * ファイルは save メソッドで保存した形式である必要があります。
     * 
     * ファイルが見つからない場合や、データが正しくない場合は null を返します。
     * その場合はエラーメッセージが画面に表示されます。
     * 
     * @param filename 読み込むファイル名(例:"save_data.txt")
     * @return 読み込んだプレイヤーオブジェクト。失敗した場合は null
     */
    public static Player load(String filename) {
        try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
            // ファイルからデータを1行ずつ読み込み
            String name = reader.readLine();                    // 1行目:名前
            int hp = Integer.parseInt(reader.readLine());       // 2行目:現在のHP
            int maxHp = Integer.parseInt(reader.readLine());    // 3行目:最大HP
            int level = Integer.parseInt(reader.readLine());    // 4行目:レベル
            // 読み込んだデータでPlayerオブジェクトを作成
            Player player = new Player(name, maxHp, level);
            player.setHp(hp);  // 現在のHPを設定(コンストラクタでは満タンになるため)
            
            System.out.println("ロード完了: " + filename);
            return player;
            
        } catch (IOException e) {
            System.out.println("ロード失敗: " + e.getMessage());
            return null;  // エラーの場合はnullを返す
        }
    }
}

ポイント:

  • writer.write() でデータを1行ずつ保存
  • reader.readLine() でデータを1行ずつ読み込み
  • Integer.parseInt()文字列を整数に変換

ステップ3: セーブ・ロード機能のテスト

実際に動かしてみましょう!

/**
 * セーブ・ロード機能のテストを行うメインクラスです。
 * プレイヤーを作成し、ファイルに保存して、再度読み込む一連の流れを確認できます。
 * 
 * このプログラムの実行手順:
 * 1. 新しいプレイヤー「勇者アレン」を作成
 * 2. プレイヤーのデータをファイルに保存
 * 3. プレイヤーのHPを変更(ダメージを受けた状態をシミュレート)
 * 4. ファイルからデータを読み込み
 * 5. 読み込んだデータが正しいか確認
 * 
 * 実行すると「save_data.txt」というファイルが作成されます。
 */
public class Main {
    /**
     * プログラムのメイン処理です。
     * セーブ・ロード機能の動作テストを実行します。
     * 
     * 実行される処理の流れ:
     * 1. プレイヤー作成 → 初期状態を表示
     * 2. セーブ実行 → ファイルに保存
     * 3. HP変更 → ダメージを受けた状態をシミュレート
     * 4. ロード実行 → ファイルから読み込み
     * 5. 結果確認 → 正しく復元されたか確認
     * 
     * @param args コマンドライン引数(このプログラムでは使用しません)
     */
    public static void main(String[] args) {
        System.out.println("========== セーブ・ロードテスト ==========\n");
        
        // 1. 新しいプレイヤーを作成(名前:勇者アレン、最大HP:100、レベル:1)
        Player player = new Player("勇者アレン", 100, 1);
        player.displayStatus();  // 初期状態を画面に表示
        
        // 2. プレイヤーのデータをファイルに保存
        System.out.println("\n--- セーブ実行 ---");
        SaveManager.save(player, "C:\\work\\java-quest\\save_data.txt"); 
        
        // 3. プレイヤーのHPを変更(戦闘でダメージを受けた状況をシミュレート)
        System.out.println("\n--- HPを減らす ---");
        player.setHp(50);  // HPを100から50に変更
        player.displayStatus();  // 変更後の状態を表示
        
        // 4. ファイルからプレイヤーデータを読み込み(セーブした時点の状態に戻る)
        System.out.println("\n--- ロード実行 ---");
        Player loadedPlayer = SaveManager.load("C:\\work\\java-quest\\save_data.txt");
        
        // 5. ロードしたプレイヤーデータを表示して確認
        if (loadedPlayer != null) {  // ロードが成功した場合のみ実行
            System.out.println("\n--- ロードしたデータ ---");
            loadedPlayer.displayStatus();  // セーブ時点の状態(HP:100)が復元されているはず
        } else {
            System.out.println("\nロードに失敗しました。ファイルが見つからないか、データが壊れています。");
        }
    }
}

実行結果

========== セーブ・ロードテスト ==========

========== ステータス ==========
名前: 勇者アレン
HP: 100/100
レベル: 1
===============================

--- セーブ実行 ---
セーブ完了: C:\work\java-quest\save_data.txt

--- HPを減らす ---
========== ステータス ==========
名前: 勇者アレン
HP: 50/100
レベル: 1
===============================

--- ロード実行 ---
ロード完了: C:\work\java-quest\save_data.txt

--- ロードしたデータ ---
========== ステータス ==========
名前: 勇者アレン
HP: 100/100
レベル: 1
===============================

保存されたファイル: C:\work\java-quest\save_data.txt

勇者アレン
100
100
1

データが1行ずつ保存されています!

ステップ4: 複数セーブスロット対応

実際のゲームでは複数のセーブデータを保存できますよね。
ファイル名を変えることで実現できます!

FileSave.java
/**
 * 複数のプレイヤーデータを作成してセーブファイルを作るクラスです。
 * ゲームのセーブスロット機能のデモを行います。
 * 
 * このプログラムで作成されるファイル:
 * - save_slot1.txt: 勇者アレンのデータ(HP:100, レベル:5)
 * - save_slot2.txt: 魔法使いエマのデータ(HP:80, レベル:3)
 * - save_slot3.txt: 戦士ブライアンのデータ(HP:150, レベル:7)
 * 
 * 使い方:
 * このプログラムを実行すると、指定したディレクトリに3つのセーブファイルが作成されます。
 * その後、SaveManager.load()で各ファイルを読み込んでテストできます。
 */
public class FileSave {
    /**
     * 複数のプレイヤーデータを作成してセーブファイルを作成します。
     * ゲームのセーブスロット機能のデモを行います。
     * 
     * 作成されるファイルの詳細:
     * - スロット1: 勇者タイプのプレイヤー(バランス型)
     * - スロット2: 魔法使いタイプのプレイヤー(HP低め、初心者向け)
     * - スロット3: 戦士タイプのプレイヤー(HP高め、上級者向け)
     * 
     * 注意:保存先のディレクトリが存在しない場合は、事前に作成しておいてください。
     * 
     * @param args コマンドライン引数(このプログラムでは使用しません)
     */
    public static void main(String[] args) {
    	
    	// 保存先のディレクトリを設定(ファイルが作成される場所)
        // 保存先のディレクトリが存在しない場合は、事前に作成する
    	String path = "C:\\work\\java-quest\\";
    	
        // セーブスロット1: 勇者タイプのプレイヤー(バランスの取れたキャラクター)
        Player player1 = new Player("勇者アレン", 100, 5);
        SaveManager.save(player1, path + "save_slot1.txt");
        
        // セーブスロット2: 魔法使いタイプのプレイヤー(HPが低めで初心者向け)
        Player player2 = new Player("魔法使いエマ", 80, 3);
        SaveManager.save(player2, path + "save_slot2.txt");
        
        // セーブスロット3: 戦士タイプのプレイヤー(HPが高く上級者向け)
        Player player3 = new Player("戦士ブライアン", 150, 7);
        SaveManager.save(player3, path + "save_slot3.txt");
        
        // 作成結果を画面に表示(どのファイルに何が保存されたか確認)
        System.out.println("\n--- 3つのセーブファイルを作成しました ---");
        System.out.println(path + "save_slot1.txt: " + player1.getName() + " (HP:" + player1.getMaxHp() + ", Lv:" + player1.getLevel() + ")");
        System.out.println(path + "save_slot2.txt: " + player2.getName() + " (HP:" + player2.getMaxHp() + ", Lv:" + player2.getLevel() + ")");
        System.out.println(path + "save_slot3.txt: " + player3.getName() + " (HP:" + player3.getMaxHp() + ", Lv:" + player3.getLevel() + ")");
        
        System.out.println("\nヒント: SaveManager.load(\"ファイル名\")で各ファイルを読み込んでテストできます。");
    }
}

実行結果:

セーブ完了: C:\work\java-quest\save_slot1.txt
セーブ完了: C:\work\java-quest\save_slot2.txt
セーブ完了: C:\work\java-quest\save_slot3.txt

--- 3つのセーブファイルを作成しました ---
save_slot1.txt: 勇者アレン (HP:100, Lv:5)
save_slot2.txt: 魔法使いエマ (HP:80, Lv:3)
save_slot3.txt: 戦士ブライアン (HP:150, Lv:7)

ヒント: SaveManager.load("ファイル名")で各ファイルを読み込んでテストできます。

練習問題

実際に手を動かして、理解を深めましょう!

練習1: プレイヤー名のみ保存

課題: プレイヤーの名前だけをファイルに保存・読み込みするプログラムを作成してください。

// ヒント
public static void saveName(String name, String filename) {
    // TODO: 名前を保存
}

public static String loadName(String filename) {
    // TODO: 名前を読み込み
    return null;
}
解答例を見る
NameSaver.java
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/**
 * プレイヤーの名前だけをファイルに保存・読み込みするシンプルなクラスです。
 * SaveManagerクラスとは異なり、名前のみを扱うため、より簡単なファイル操作を学ぶことができます。
 * 
 * 使い方の例:
 * // 名前を保存
 * NameSaver.saveName("勇者アレン", "player_name.txt");
 * 
 * // 名前を読み込み
 * String name = NameSaver.loadName("player_name.txt");
 * 
 * 保存先:C:\\work\\java-quest\\ディレクトリ
 * 
 */
public class NameSaver {
		
    /**
     * プレイヤーの名前をテキストファイルに保存します。
     * ファイルには名前だけが1行で書き込まれます。
     * 
     * 保存されるファイルの中身の例:
     * 勇者アレン
     * 
     * @param name 保存したいプレイヤーの名前(例:"勇者アレン")
     * @param filename 保存先のファイル名(例:"player_name.txt")
     */
    public static void saveName(String name, String filename) {
    	
        try (FileWriter writer = new FileWriter(filename)) {
            writer.write(name);  // 名前だけをファイルに書き込み
            System.out.println("名前を保存: " + name + " -> " +filename);
        } catch (IOException e) {
            System.out.println("保存失敗: " + e.getMessage());
        }
    }
    
    /**
     * テキストファイルからプレイヤーの名前を読み込みます。
     * ファイルの1行目に書かれた名前を取得します。
     * 
     * ファイルが存在しない場合や読み込みに失敗した場合は null を返します。
     * 
     * @param filename 読み込むファイル名(例:"player_name.txt")
     * @return 読み込んだプレイヤーの名前。失敗した場合は null
     */
    public static String loadName(String filename) {
        try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
            String name = reader.readLine();  // ファイルの1行目を読み込み
            System.out.println("名前を読み込み: " + name + " <- " + filename);
            return name;
        } catch (IOException e) {
            System.out.println("読み込み失敗: " + e.getMessage());
            return null;  // エラーの場合はnullを返す
        }
    }
    
    /**
     * NameSaverクラスの動作テストを行います。
     * 名前の保存と読み込みの一連の流れを確認できます。
     * 
     * 実行される処理:
     * 1. "勇者アレン"という名前を"player_name.txt"に保存
     * 2. 保存したファイルから名前を読み込み
     * 3. 読み込んだ名前を画面に表示
     * 
     * @param args コマンドライン引数(このプログラムでは使用しません)
     */
    public static void main(String[] args) {
        System.out.println("========== 名前保存テスト ==========\n");
        
        // 1. 名前をファイルに保存
        String file = "data/player_name.txt";
        System.out.println("--- 名前保存 ---");
        saveName("勇者アレン", file);
        
        // 2. 保存した名前を読み込み
        System.out.println("\n--- 名前読み込み ---");
        String name = loadName(file);
        
        // 3. 結果を表示
        if (name != null) {
            System.out.println("\n--- 結果 ---");
            System.out.println("プレイヤー名: " + name);
            System.out.println("テスト成功!名前の保存と読み込みが正常に動作しました。");
        } else {
            System.out.println("\nテスト失敗:名前の読み込みに失敗しました。");
        }
    }
}

実行結果

========== 名前保存テスト ==========

--- 名前保存 ---
名前を保存: 勇者アレン -> C:\work\java-quest\player_name.txt

--- 名前読み込み ---
名前を読み込み: 勇者アレン <- C:\work\java-quest\player_name.txt

--- 結果 ---
プレイヤー名: 勇者アレン
テスト成功!名前の保存と読み込みが正常に動作しました。

練習2: HP/MP/レベルの保存

課題: HP、MP、レベルの3つのデータを保存・読み込みするプログラムを作成してください。

// ヒント: カンマ区切りで保存
// 例: 100,50,5
解答例を見る
StatusSaver.java
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/**
 * プレイヤーのステータス(HP、MP、レベル)をCSV形式で保存・読み込みするクラスです。
 * データをカンマ区切りで保存するため、シンプルで読みやすいファイル形式を学ぶことができます。
 * 
 * 保存形式:CSV(Comma Separated Values)
 * ファイルの中身の例:100,50,5(HP,MP,レベルの順)
 * 
 * 使い方の例:
 * // ステータスを保存
 * StatusSaver.save(100, 50, 5, "status.txt");
 * 
 * // ステータスを読み込み
 * int[] status = StatusSaver.load("status.txt");
 * int hp = status[0], mp = status[1], level = status[2];
 * 
 */
public class StatusSaver {
    /**
     * プレイヤーのステータスをCSV形式でファイルに保存します。
     * HP、MP、レベルをカンマで区切って1行で保存します。
     * 
     * 保存されるファイルの中身の例:
     * 100,50,5
     * (HP:100、MP:50、レベル:5の意味)
     * 
     * @param hp プレイヤーのHP(体力)
     * @param mp プレイヤーのMP(魔法力)
     * @param level プレイヤーのレベル
     * @param filename 保存先のファイル名(例:"status.txt")
     */
    public static void save(int hp, int mp, int level, String filename) {
        try (FileWriter writer = new FileWriter(filename)) {
            // HP、MP、レベルをカンマ区切りで保存(CSV形式)
            writer.write(hp + "," + mp + "," + level);
            System.out.println("ステータス保存完了: HP=" + hp + ", MP=" + mp + ", Level=" + level);
        } catch (IOException e) {
            System.out.println("保存失敗: " + e.getMessage());
        }
    }
    
    /**
     * CSV形式で保存されたステータスデータをファイルから読み込みます。
     * カンマで区切られたデータを分割して、整数の配列として返します。
     * 
     * 返される配列の構造:
     * - status[0]: HP(体力)
     * - status[1]: MP(魔法力)
     * - status[2]: Level(レベル)
     * 
     * ファイルが存在しない場合やデータが正しくない場合は null を返します。
     * 
     * @param filename 読み込むファイル名(例:"status.txt")
     * @return ステータスデータの配列[HP, MP, Level]。失敗した場合は null
     */
    public static int[] load(String filename) {
        try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
            String line = reader.readLine();  // ファイルの1行目を読み込み
            String[] parts = line.split(",");     // カンマで文字列を分割
            
            // 分割した文字列を整数に変換
            int hp = Integer.parseInt(parts[0]);     // 1番目:HP
            int mp = Integer.parseInt(parts[1]);     // 2番目:MP
            int level = Integer.parseInt(parts[2]);   // 3番目:レベル
            
            System.out.println("ステータス読み込み完了: HP=" + hp + ", MP=" + mp + ", Level=" + level);
            return new int[]{hp, mp, level};  // 配列として返す
            
        } catch (IOException e) {
            System.out.println("読み込み失敗: " + e.getMessage());
            return null;  // エラーの場合はnullを返す
            
        } catch (NumberFormatException e) {
            System.out.println("データ形式エラー: 数値ではないデータが含まれています");
            return null;
            
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("データ不足エラー: HP、MP、レベルの3つのデータが必要です");
            return null;
        }
    }
    
    /**
     * StatusSaverクラスの動作テストを行います。
     * CSV形式でのステータス保存と読み込みの一連の流れを確認できます。
     * 
     * 実行される処理:
     * 1. サンプルステータス(HP:100, MP:50, Level:5)を"status.txt"に保存
     * 2. 保存したファイルからステータスを読み込み
     * 3. 読み込んだデータを個別に表示して確認
     * 
     * @param args コマンドライン引数(このプログラムでは使用しません)
     */
    public static void main(String[] args) {
    	System.out.println("========== ステータス保存テスト ==========\n");
    	
    	// 保存先ファイルのパスを設定
    	String file = "data/status.txt";
    	
        // 1. サンプルステータスをCSV形式で保存
        System.out.println("--- ステータス保存 ---");
        save(100, 50, 5, file);  // HP:100, MP:50, Level:5を保存
        
        // 2. 保存したステータスを読み込み
        System.out.println("\n--- ステータス読み込み ---");
        int[] status = load(file);
        
        // 3. 読み込んだデータを表示して確認
        if (status != null) {
            System.out.println("\n--- 結果 ---");
            System.out.println("HP: " + status[0] + " (体力)");
            System.out.println("MP: " + status[1] + " (魔法力)");
            System.out.println("Level: " + status[2] + " (レベル)");
            System.out.println("\nテスト成功!CSV形式でのステータス保存と読み込みが正常に動作しました。");
        } else {
            System.out.println("\nテスト失敗:ステータスの読み込みに失敗しました。");
        }
    }
}

実行結果

========== ステータス保存テスト ==========

--- ステータス保存 ---
ステータス保存完了: HP=100, MP=50, Level=5

--- ステータス読み込み ---
ステータス読み込み完了: HP=100, MP=50, Level=5

--- 結果 ---
HP: 100 (体力)
MP: 50 (魔法力)
Level: 5 (レベル)

テスト成功!CSV形式でのステータス保存と読み込みが正常に動作しました。

練習3: 装備情報の保存

課題: プレイヤーの装備情報(武器名、防具名)を追加で保存してください。

解答例を見る
Player.java
/**
 * ゲームのプレイヤーを表すクラスです。
 * プレイヤーの名前、HP(体力)、レベル、装備情報(武器、防具)などの情報を管理します。
 * 
 * 使い方の例:
 * Player player = new Player("勇者", 100, 1);
 * player.setWeapon("鉄の剣");  // 武器を装備
 * player.setArmor("革の防具");   // 防具を装備
 * player.displayStatus(); // プレイヤーの情報を表示
 */
public class Player {
    /** プレイヤーの名前(例:"勇者"、"魔法使い"など) */
    private String name;
    
    /** 現在のHP(体力)。0になると倒れてしまいます */
    private int hp;
    
    /** 最大HP(体力の上限)。回復するときの目安になります */
    private int maxHp;
    
    /** プレイヤーのレベル。強さを表します */
    private int level;
    
    /** 装備中の武器名(例:"鉄の剣"、"魔法の杖"など)。攻撃力に影響します */
    private String weapon;  // 追加
    
    /** 装備中の防具名(例:"革の防具"、"鉄の鎧"など)。防御力に影響します */
    private String armor;  // 追加

    /**
     * 新しいプレイヤーを作成します。
     * 作成時は体力が満タンの状態でスタートします。
     * 装備は初期状態では何も装備していない状態(null)です。
     * 
     * @param name プレイヤーの名前(例:"勇者")
     * @param maxHp 最大HP(体力の上限、例:100)
     * @param level プレイヤーのレベル(例:1)
     */
    public Player(String name, int maxHp, int level) {
        this.name = name;
        this.maxHp = maxHp;
        this.hp = maxHp;  // 最初は体力満タン
        this.level = level;
        this.weapon = "";  // 追加:最初は未装備
        this.armor = "";  // 追加:最初は未装備
    }
    
    /**
     * プレイヤーの名前を取得します。
     * @return プレイヤーの名前
     */
    public String getName() { return name; }
    
    /**
     * 現在のHPを取得します。
     * @return 現在のHP(0以上の数値)
     */
    public int getHp() { return hp; }
    
    /**
     * 最大HPを取得します。
     * @return 最大HP(体力の上限値)
     */
    public int getMaxHp() { return maxHp; }
    
    /**
     * プレイヤーのレベルを取得します。
     * @return 現在のレベル
     */
    public int getLevel() { return level; }
    
    /**
     * 装備中の武器名を取得します。
     * @return 装備中の武器名。武器を装備していない場合は null
     */
    public String getWeapon() { return weapon; }
    
    /**
     * 装備中の防具名を取得します。
     * @return 装備中の防具名。防具を装備していない場合は null
     */
    public String getArmor() { return armor; }
    
    /**
     * プレイヤーのHPを設定します。
     * ダメージを受けたり、回復したりするときに使います。
     * 
     * 注意:HPは0未満にならないように、また最大HPを超えないように
     * 呼び出し側で調整してください。
     * 
     * @param hp 設定したいHP(0以上、maxHp以下が推奨)
     */
    public void setHp(int hp) { this.hp = hp; }
    
    /**
     * プレイヤーの武器を装備します。
     * 新しい武器を装備すると、以前の武器は自動的に外れます。
     * 
     * @param weapon 装備したい武器名(例:"鉄の剣")。nullを指定すると武器を外します
     */
    public void setWeapon(String weapon) { 
    	if(weapon != null) 	this.weapon = weapon; 
    }
    
    /**
     * プレイヤーの防具を装備します。
     * 新しい防具を装備すると、以前の防具は自動的に外れます。
     * 
     * @param armor 装備したい防具名(例:"革の防具")。nullを指定すると防具を外します
     */
    public void setArmor(String armor) { 
    	if(armor != null) this.armor = armor; 
    }

    /**
     * プレイヤーの現在の状態を画面に表示します。
     * 名前、HP、レベル、装備情報を見やすい形で出力します。
     * 
     * 表示例:
     * ========== ステータス ==========
     * 名前: 勇者
     * HP: 80/100
     * レベル: 5
     * 武器: 鉄の剣
     * 防具: 革の防具
     * ===============================
     */
    public void displayStatus() {
        System.out.println("========== ステータス ==========");
        System.out.println("名前: " + name);
        System.out.println("HP: " + hp + "/" + maxHp);
        System.out.println("レベル: " + level);
        
        // 装備情報を表示(装備していない場合は"なし"と表示)
        System.out.println("武器: " + (weapon.isEmpty() ? "なし" : weapon));
        System.out.println("防具: " + (armor.isEmpty() ?  "なし"  : armor));
        
        System.out.println("===============================");
    }
    
}
SaveManager.java
public class SaveManager {
    public static void save(Player player, String filename) {
        try (FileWriter writer = new FileWriter(filename)) {
            writer.write(player.getName() + "\n");
            writer.write(player.getHp() + "\n");
            writer.write(player.getMaxHp() + "\n");
            writer.write(player.getLevel() + "\n");
            writer.write(player.getWeapon() + "\n");  // 追加
            writer.write(player.getArmor() + "\n");   // 追加
            
            System.out.println("セーブ完了(装備含む)");
        } catch (IOException e) {
            System.out.println("セーブ失敗");
        }
    }
    
    public static Player load(String filename) {
        try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
            String name = reader.readLine();
            int hp = Integer.parseInt(reader.readLine());
            int maxHp = Integer.parseInt(reader.readLine());
            int level = Integer.parseInt(reader.readLine());
            String weapon = reader.readLine();  // 追加
            String armor = reader.readLine();   // 追加
            
            Player player = new Player(name, maxHp, level, weapon, armor);
            player.setHp(hp);
            player.setWeapon(weapon);  // 武器を装備
            player.setArmor(armor);    // 防具を装備
             
            System.out.println("ロード完了(装備含む)");
            return player;
            
        } catch (IOException e) {
            System.out.println("ロード失敗");
            return null;
        }
    }
}

まとめ

今回学んだこと

内容 説明
ファイル入出力 データを永続化する技術
FileWriter ファイルに書き込む
FileReader + BufferedReader ファイルから読み込む
try-with-resources 自動で close() してくれる
セーブ・ロード ゲームデータの保存・復元

重要ポイント

1. try-with-resources を使おう

// これを使う!
try (FileWriter writer = new FileWriter("file.txt")) {
    writer.write("データ");
}  // 自動で close()

2. 例外処理は必須

try {
    // ファイル操作
} catch (IOException e) {
    // エラー処理
}

3. データ形式を統一

// 保存時と読み込み時の順番を一致させる
writer.write(name + "\n");
writer.write(hp + "\n");

String name = reader.readLine();
int hp = Integer.parseInt(reader.readLine());

実用例

今回学んだ技術は、以下のような場面で使われます:

  • ゲームのセーブ機能
  • メモ帳アプリ
  • データのエクスポート
  • 設定の保存

次回予告

次回は 「例外処理 - エラーハンドリング」 を学びます!

今回作ったセーブ・ロード機能には、まだ問題があります:

  • ファイルが存在しない場合
  • データが壊れている場合
  • 権限がない場合

これらのエラーに対応する方法を学びましょう!

📚 参考資料

公式ドキュメント

関連記事

  • Java Quest Part 1 - 完全版

  • Java Quest Part 2 - 第2回: 例外処理 (次回)

お疲れさまでした!

今回でセーブ・ロード機能が実装できました!
次回はエラーに強いプログラムを作りましょう!


© 2026 Java Quest - オブジェクト指向って何?RPGで理解する超入門 Part2
All Rights Reserved.

本記事は教育目的で作成されています。RPGの例を通じてプログラミング概念を楽しく学習できることを目指しています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?