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

Web APP Java
スポンサーリンク

4日目のゴール

4日目のテーマは
「ファイルを“読みっぱなし・書きっぱなし”から、“更新できるデータ”として扱う」 ことです。

1〜3日目であなたは、

ファイルに文字を書いて永続化する
追記モードで履歴を溜める
1行=1レコードとして構造を持たせる(ID|日付|本文)

というところまで来ました。

4日目では一歩進んで、

「特定のIDのメモだけ削除する」
「特定のIDのメモだけ編集する」

という、「更新」の感覚をつかみに行きます。

ここで大事なのは、

ファイルは「途中だけ書き換える」が苦手
だから「読み込んで、作り直す」という発想を持つ

という考え方です。


ファイルは「途中だけ書き換える」が苦手、という現実

メモリとファイルの“書き換えやすさ”の違い

配列やリストなら、
「3番目だけ書き換える」は簡単です。

list.set(2, "新しい値");

で終わりです。

でも、テキストファイルは違います。

ファイルの真ん中あたりにある
「3行目だけ」を直接書き換える、というのは
基本的にはやりません(やりにくいし、壊れやすい)。

代わりに、こう考えます。

全部読み込む
必要な行だけ残す・書き換える
新しい内容でファイルを作り直す

つまり、
「部分更新」ではなく「再構築」 という発想です。

「一度全部読む → 新しいファイルを作る」という基本パターン

削除も編集も、
実はやっていることは同じです。

元のファイルを1行ずつ読む
その行をどう扱うか決める
新しいファイルに「残したい行」だけを書き出す

削除なら「そのIDの行だけ書き出さない」
編集なら「そのIDの行だけ書き換えて書き出す」

このパターンを、今日は体に入れていきます。


今日の題材:ID指定で「削除」と「編集」ができるメモアプリ

アプリのイメージ

3日目の「ID+日付+本文」アプリに、
メニューを増やします。

「1: メモを追加」
「2: メモ一覧を表示」
「3: メモを削除」
「4: メモを編集」
「0: 終了」

削除では、
「削除したいID」を入力してもらい、
そのIDの行だけを除いてファイルを作り直します。

編集では、
「編集したいID」と「新しい本文」を入力してもらい、
そのIDの行だけを書き換えてファイルを作り直します。


削除の考え方:そのIDの行だけ“書き出さない”

削除の流れを言葉で整理する

ID 3 のメモを削除したいとします。

今のファイルがこうだとします。

1|2026-06-06|A
2|2026-06-07|B
3|2026-06-08|C
4|2026-06-09|D

やりたいことは、
「3 の行だけ消して、1,2,4 は残す」です。

流れはこうです。

元のファイルを1行ずつ読む
行を split して ID を取り出す
ID が 3 なら、その行は新しいファイルに書かない
それ以外の行は、新しいファイルにそのまま書く
最後に、新しいファイルで元のファイルを置き換える

この「書き出さない」というのが削除の本質です。

削除のコード(シンプル版)

private static void deleteMemo(Scanner scanner) {
    System.out.print("削除したいメモのIDを入力してください: ");
    String idStr = scanner.nextLine();

    if (idStr.isEmpty()) {
        System.out.println("ID が入力されていません。");
        return;
    }

    int targetId;
    try {
        targetId = Integer.parseInt(idStr);
    } catch (NumberFormatException e) {
        System.out.println("ID は整数で入力してください。");
        return;
    }

    String tempFileName = "memo_temp.txt";
    boolean deleted = false;

    try (BufferedReader reader = new BufferedReader(new FileReader(FILE_NAME));
         BufferedWriter writer = new BufferedWriter(new FileWriter(tempFileName))) {

        String line;
        while ((line = reader.readLine()) != null) {
            String[] parts = line.split("\\|", 3);
            if (parts.length >= 1) {
                try {
                    int id = Integer.parseInt(parts[0]);
                    if (id == targetId) {
                        deleted = true;
                        continue;
                    }
                } catch (NumberFormatException e) {
                    // ID が数字でない行は、そのまま残す
                }
            }
            writer.write(line);
            writer.newLine();
        }
    } catch (IOException e) {
        System.out.println("削除処理中にエラーが発生しました。");
        System.out.println("(開発者向け情報)" + e.getMessage());
        return;
    }

    if (!deleted) {
        System.out.println("指定されたIDのメモが見つかりませんでした。");
        new java.io.File(tempFileName).delete();
        return;
    }

    java.io.File original = new java.io.File(FILE_NAME);
    java.io.File temp = new java.io.File(tempFileName);

    if (original.delete() && temp.renameTo(original)) {
        System.out.println("ID " + targetId + " のメモを削除しました。");
    } else {
        System.out.println("ファイルの置き換えに失敗しました。");
    }
}
Java

ここでの重要ポイントを、丁寧に見ていきます。


一時ファイルを使う理由と流れ

なぜ「一時ファイル」を使うのか

直接 memo.txt を書き換えるのではなく、
memo_temp.txt という一時ファイルを使っています。

理由はシンプルです。

元のファイルを読みながら
同じファイルに書き込むと
中身がぐちゃぐちゃになりやすい

だから、

元のファイルは「読み専用」にする
新しい内容は「別ファイル」に書く
最後に「新しいファイルで元のファイルを置き換える」

という安全な手順を踏みます。

一時ファイルを使った更新の3ステップ

削除も編集も、基本はこの3ステップです。

元ファイルを読みながら、一時ファイルに「新しい内容」を書く
処理が成功したら、元ファイルを削除する
一時ファイルの名前を、元ファイルの名前に変える

コードでは、ここにあたります。

java.io.File original = new java.io.File(FILE_NAME);
java.io.File temp = new java.io.File(tempFileName);

if (original.delete() && temp.renameTo(original)) {
    // 成功
} else {
    // 失敗
}
Java

この流れを覚えておくと、
「ファイルの更新」は怖くなくなります。


編集の考え方:そのIDの行だけ“書き換えて書き出す”

編集の流れを言葉で整理する

ID 3 のメモを「新しい本文」に変えたいとします。

今のファイルがこうだとします。

1|2026-06-06|A
2|2026-06-07|B
3|2026-06-08|C
4|2026-06-09|D

やりたいことは、
「3 の行だけ本文を変えて、他はそのまま」です。

流れはこうです。

元のファイルを1行ずつ読む
行を split して ID を取り出す
ID が 3 なら、「新しい本文」を使って行を組み立て直す
それ以外の行は、そのまま書き出す
最後に、一時ファイルで元のファイルを置き換える

削除との違いは、

削除 → 「その行を書き出さない」
編集 → 「その行を書き換えて書き出す」

というだけです。

編集のコード(シンプル版)

private static void editMemo(Scanner scanner) {
    System.out.print("編集したいメモのIDを入力してください: ");
    String idStr = scanner.nextLine();

    if (idStr.isEmpty()) {
        System.out.println("ID が入力されていません。");
        return;
    }

    int targetId;
    try {
        targetId = Integer.parseInt(idStr);
    } catch (NumberFormatException e) {
        System.out.println("ID は整数で入力してください。");
        return;
    }

    System.out.print("新しい本文を入力してください: ");
    String newBody = scanner.nextLine();
    if (newBody.isEmpty()) {
        System.out.println("空の本文には編集しません。");
        return;
    }

    String tempFileName = "memo_temp.txt";
    boolean edited = false;

    try (BufferedReader reader = new BufferedReader(new FileReader(FILE_NAME));
         BufferedWriter writer = new BufferedWriter(new FileWriter(tempFileName))) {

        String line;
        while ((line = reader.readLine()) != null) {
            String[] parts = line.split("\\|", 3);
            if (parts.length == 3) {
                try {
                    int id = Integer.parseInt(parts[0]);
                    String date = parts[1];
                    String body = parts[2];

                    if (id == targetId) {
                        String newLine = id + "|" + date + "|" + newBody;
                        writer.write(newLine);
                        writer.newLine();
                        edited = true;
                        continue;
                    }
                } catch (NumberFormatException e) {
                    // ID が数字でない行は、そのまま書き出す
                }
            }

            writer.write(line);
            writer.newLine();
        }
    } catch (IOException e) {
        System.out.println("編集処理中にエラーが発生しました。");
        System.out.println("(開発者向け情報)" + e.getMessage());
        return;
    }

    if (!edited) {
        System.out.println("指定されたIDのメモが見つかりませんでした。");
        new java.io.File(tempFileName).delete();
        return;
    }

    java.io.File original = new java.io.File(FILE_NAME);
    java.io.File temp = new java.io.File(tempFileName);

    if (original.delete() && temp.renameTo(original)) {
        System.out.println("ID " + targetId + " のメモを編集しました。");
    } else {
        System.out.println("ファイルの置き換えに失敗しました。");
    }
}
Java

4日目版:追加・一覧・削除・編集ができるアプリ全体

全体像をまとめたコード

メニューだけざっくり示します。
中身は、3日目の addMemo と、今日の deleteMemoeditMemo を組み合わせた形です。

public class FileSaveAppDay4 {
    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("=== ファイル保存アプリ 4日目 ===");
            System.out.println("1: メモを追加");
            System.out.println("2: メモ一覧を表示");
            System.out.println("3: メモを削除");
            System.out.println("4: メモを編集");
            System.out.println("0: 終了");
            System.out.print("番号を選んでください: ");

            String choice = scanner.nextLine();

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

        scanner.close();
    }

    // addMemo, showAllMemos, deleteMemo, editMemo はここまで説明したもの
}
Java

ここまで来ると、
ファイルはもう「ただの保存場所」ではなく、
「追加・一覧・削除・編集ができる、小さなデータストア」
として扱えるようになっています。


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

ファイル更新は「部分書き換え」ではなく「再構築」

今日いちばん大事なのは、
「ファイルの更新=一度全部読んで、新しく作り直す」
という感覚です。

削除 → その行だけ書き出さない
編集 → その行だけ書き換えて書き出す

どちらも、

元ファイルを読みながら
一時ファイルに「新しい姿」を書いていく
最後に一時ファイルで元ファイルを置き換える

という同じパターンで実現できます。

このパターンを覚えておくと、
ToDo アプリでも、家計簿でも、
「特定の行だけ削除・編集したい」という要求に
落ち着いて応えられるようになります。

永続化は「データのライフサイクルを設計する」こと

3日目までで、
「どう保存するか」「どう読むか」を考えました。

4日目では、
「どう更新するか」「どう消すか」まで踏み込みました。

追加 → 一番下に追記
一覧 → 全行を読み込んで表示
削除 → その行を除いて再構築
編集 → その行を書き換えて再構築

ここまで考えられるようになると、
永続化はもう「ただのファイル操作」ではなく、
「データの一生(ライフサイクル)を設計すること」
として見えてきます。

その視点を持てている時点で、
あなたはもう、かなり“アプリ開発者の目線”に近づいています。

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