Java | 1 日 90 分 × 7 日アプリ学習 初級編:ファイル保存アプリ

Web APP Java
スポンサーリンク

1日目のゴール

1日目のテーマは
「ファイルに“文字”を書いて、“あとから読み返せる”感覚をつかむこと」 です。

今日はまだ「完璧な設計」は目指しません。
まずはこう思えたら勝ちです。

「メモをファイルに保存して、プログラムを終了しても残っている」
「次に起動したとき、そのメモを読み込める」

これが「永続化(えいぞくか)」の一番シンプルな姿です。


永続化って何?メモ帳との違いから考える

メモリは「消える世界」、ファイルは「残る世界」

Java のプログラムが動いているとき、
変数やオブジェクトは「メモリ」という場所に置かれています。

String memo = "こんにちは";
と書けば、memo という変数に文字列が入りますが、
プログラムを終了した瞬間、それは消えます。

一方、ファイルはこうです。

テキストファイルに「こんにちは」と書いて保存する
パソコンを再起動しても、そのファイルは残っている

この「プログラムが終わっても残る」ことを
永続化(えいぞくか) と呼びます。

なぜ永続化が必要なのか

ToDo アプリ、日記アプリ、家計簿アプリ…
どれも「次に開いたときに前のデータが残っていてほしい」ですよね。

メモリだけに持っていると、
アプリを閉じた瞬間に全部消えてしまいます。

だから、

アプリの中のデータ
→ ファイル(またはデータベース)に書き出す
→ 次回起動時に読み込む

という流れが必要になります。

1日目は、その「一番小さい版」として、
テキストファイルへの保存と読み込み をやります。


今日の題材:1行メモを保存・読み込みするミニアプリ

何を作るか

コンソールで動く、超シンプルなアプリを作ります。

メニューを表示する
「1: メモを保存」「2: メモを読み込み」「0: 終了」
保存では、1行のメモを入力してファイルに書き込む
読み込みでは、そのファイルから1行読み出して表示する

まずは「1行だけ」でいいです。
ここで大事なのは、
「書いたものが、プログラムを終了しても残る」 という体験です。


ファイルに書き込む基本:FileWriter と BufferedWriter

まずは「書き込みだけ」のサンプル

ファイルに文字を書き込む最小コードを見てみましょう。

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class SimpleWrite {
    public static void main(String[] args) {
        String fileName = "memo.txt";
        String text = "こんにちは、ファイル保存!";

        try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))) {
            writer.write(text);
            writer.newLine(); // 改行を入れる(おまけ)
            System.out.println("書き込みが完了しました。");
        } catch (IOException e) {
            System.out.println("ファイルへの書き込みに失敗しました。");
            System.out.println("(開発者向け情報)" + e.getMessage());
        }
    }
}
Java

ここで出てきたクラスを、かみ砕いて説明します。

FileWriter と BufferedWriter の役割

FileWriter
指定したファイルに「文字」を書くためのクラスです。
new FileWriter("memo.txt") とすると、
カレントディレクトリに memo.txt というファイルを開きます(なければ作る)。

BufferedWriter
FileWriter に「バッファ(クッション)」をつけて、
効率よく書き込むためのクラスです。
細かいことは今は気にしなくてOKで、
「FileWriter を包んで使うのが定番」と覚えておけば十分です。

try-with-resources の意味(超重要)

try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))) {
    // 書き込み処理
}
Java

この書き方は try-with-resources と呼ばれます。

ポイントは一つ。

ブロックを抜けるときに、自動で writer.close() してくれる

ファイルやネットワークのような「開いたら閉じる必要があるもの」は、
閉じ忘れると不具合の原因になります。

try-with-resources を使うと、
例外が起きても起きなくても、
最後に必ず close してくれるので、とても安全です。


ファイルから読み込む基本:FileReader と BufferedReader

「読み込みだけ」のサンプル

次は、ファイルから1行読み込むコードです。

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

public class SimpleRead {
    public static void main(String[] args) {
        String fileName = "memo.txt";

        try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
            String line = reader.readLine();
            if (line == null) {
                System.out.println("ファイルは空です。");
            } else {
                System.out.println("読み込んだ内容: " + line);
            }
        } catch (IOException e) {
            System.out.println("ファイルの読み込みに失敗しました。");
            System.out.println("(開発者向け情報)" + e.getMessage());
        }
    }
}
Java

FileReader と BufferedReader の役割

FileReader
指定したファイルから「文字」を読み込むためのクラスです。

BufferedReader
FileReader を包んで、
readLine() で「1行ずつ」読み込めるようにしてくれるクラスです。

readLine() は、

行があれば、その行の文字列を返す
ファイルの終わりまで来たら null を返す

という動きをします。

1日目では、
「とりあえず1行だけ読む」
という使い方で十分です。


保存アプリ1日目版:1行メモ保存+読み込み

全体のイメージ

ここまでの部品を組み合わせて、
1日目の「ファイル保存アプリ」を作ります。

やることはシンプルです。

メニューを表示
1 → メモを入力して保存
2 → 保存されたメモを読み込み
0 → 終了

コードを見てから、重要ポイントを解説します。

コード全体

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;

public class FileSaveApp {
    private static final String FILE_NAME = "memo.txt";

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        while (true) {
            System.out.println();
            System.out.println("=== ファイル保存アプリ 1日目 ===");
            System.out.println("1: メモを保存");
            System.out.println("2: メモを読み込み");
            System.out.println("0: 終了");
            System.out.print("番号を選んでください: ");

            String choice = scanner.nextLine();

            if ("0".equals(choice)) {
                System.out.println("終了します。");
                break;
            } else if ("1".equals(choice)) {
                saveMemo(scanner);
            } else if ("2".equals(choice)) {
                loadMemo();
            } else {
                System.out.println("不正な入力です。0, 1, 2 のいずれかを入力してください。");
            }
        }

        scanner.close();
    }

    private static void saveMemo(Scanner scanner) {
        System.out.print("保存したいメモを1行で入力してください: ");
        String memo = scanner.nextLine();

        if (memo.isEmpty()) {
            System.out.println("空のメモは保存しません。");
            return;
        }

        try (BufferedWriter writer = new BufferedWriter(new FileWriter(FILE_NAME))) {
            writer.write(memo);
            writer.newLine();
            System.out.println("メモをファイルに保存しました。ファイル名: " + FILE_NAME);
        } catch (IOException e) {
            System.out.println("メモの保存に失敗しました。");
            System.out.println("(開発者向け情報)" + e.getMessage());
        }
    }

    private static void loadMemo() {
        try (BufferedReader reader = new BufferedReader(new FileReader(FILE_NAME))) {
            String line = reader.readLine();
            if (line == null) {
                System.out.println("ファイルは空です。まだメモが保存されていません。");
            } else {
                System.out.println("保存されているメモ: " + line);
            }
        } catch (IOException e) {
            System.out.println("メモの読み込みに失敗しました。まだ保存されていないか、ファイルにアクセスできません。");
            System.out.println("(開発者向け情報)" + e.getMessage());
        }
    }
}
Java

重要ポイントをかみ砕いて解説する

1つのファイル名を定数で持つ

private static final String FILE_NAME = "memo.txt";
Java

ここは地味ですが、かなり大事です。

ファイル名をあちこちにベタ書きすると、
後で名前を変えたくなったときに全部直す必要が出てきます。

FILE_NAME という定数にしておけば、
「どのファイルに保存しているか」が一目で分かるし、
変更も1か所で済みます。

保存処理:上書き保存のシンプル版

try (BufferedWriter writer = new BufferedWriter(new FileWriter(FILE_NAME))) {
    writer.write(memo);
    writer.newLine();
    System.out.println("メモをファイルに保存しました。ファイル名: " + FILE_NAME);
} catch (IOException e) {
    System.out.println("メモの保存に失敗しました。");
    System.out.println("(開発者向け情報)" + e.getMessage());
}
Java

ここでのポイントは二つです。

new FileWriter(FILE_NAME) は「上書きモード」
→ すでにファイルがあれば中身を消して書き直す
→ 1日目は「最新の1件だけ保存」で十分

try-with-resources で writer を自動 close
→ 閉じ忘れを防げる
→ 例外が起きても確実に片付く

「追記モード(append)」は、
new FileWriter(FILE_NAME, true) と書きますが、
それは2日目以降のテーマに回しましょう。

読み込み処理:ファイルが空のときの扱い

String line = reader.readLine();
if (line == null) {
    System.out.println("ファイルは空です。まだメモが保存されていません。");
} else {
    System.out.println("保存されているメモ: " + line);
}
Java

readLine()null を返すのは、
「ファイルの終わりまで来た」ことを意味します。

1日目のアプリでは、

ファイルが存在するが中身が空 → 「まだメモが保存されていません」と表示
1行以上あれば、最初の1行だけ表示

というシンプルな仕様にしています。

例外メッセージの扱い(軽くおさらい)

} catch (IOException e) {
    System.out.println("メモの読み込みに失敗しました。まだ保存されていないか、ファイルにアクセスできません。");
    System.out.println("(開発者向け情報)" + e.getMessage());
}
Java

ユーザー向けには、
「何が起きたか」「どういう可能性があるか」をざっくり伝える。

開発者向けには、
e.getMessage() で技術的な詳細を表示する。

本番アプリなら、
この「開発者向け情報」はログに出すことが多いです。


1日目で“体に入れてほしい感覚”

「メモリの中」と「ファイルの中」を意識して分ける

このアプリで起きていることを、
頭の中で二つの世界に分けてみてください。

プログラムが動いている間だけの世界(メモリ)
Scanner で入力した文字列
memo 変数の中身

プログラムが終わっても残る世界(ファイル)
memo.txt の中に書かれた文字

writer.write(memo); の一行は、
「メモリの中の文字列を、ファイルという“残る世界”にコピーする」
という意味です。

逆に reader.readLine(); は、
「ファイルという“残る世界”から、メモリに1行分コピーする」
という意味です。

このイメージが持てたら、
もう永続化の入り口には立てています。


1日目のまとめと、次へのつながり

今日は、

ファイルに文字を書き込む(FileWriter / BufferedWriter)
ファイルから文字を読み込む(FileReader / BufferedReader)
try-with-resources で「開いたら閉じる」を自動化する
1行メモを保存・読み込みするミニアプリを作る

ところまで来ました。

ここから先は、例えばこんな方向に広げていけます。

複数行のメモを保存する(追記モード)
ToDo リストを1行1タスクで保存する
「保存」と「読み込み」を例外処理と組み合わせて堅くする

でも、1日目で一番大事なのは、
「あ、ファイルに書いたら、本当に残るんだ」
という小さな感動です。

そこさえつかめていれば、
あとは「何を保存したいか」を変えていくだけで、
どんどんアプリっぽいものが作れるようになります。

タイトルとURLをコピーしました