Java / LESSON 14 / JV14

Java:ファイル入出力

1学習の目的

2基礎解説

これまでのプログラムは、終了するとデータが消えていました。ファイルに保存すれば、次回起動時に読み込める——CSVの取り込み、ログの出力、設定の保存など、実務では必須の操作です。

やりたいこと書き方備考
書き込むFiles.writeString(path, text)上書き
全部読むFiles.readString(path)小さいファイル向け
行ごとに読むFiles.readAllLines(path)List で返る
存在確認Files.exists(path)読む前に確認
✅ 覚えるべき重要ポイント
  1. ファイル操作は必ず IOException を伴う。try-catch で囲むか、throws IOException を宣言する必要がある——失敗を無視できない設計になっている。
  2. Path.of("ファイル名") でパスを作る。現代のJavaでは Files クラスと組み合わせるのが標準的な書き方。
  3. writeString は既存の内容を消して上書きする。追記したいなら StandardOpenOption.APPEND を渡す。
  4. try-with-resources なら自動で閉じてくれるtry (リソース) { … } と書けば、正常終了でも例外発生でも確実にクローズされる。
  5. 存在しないファイルを読むと NoSuchFileException。読む前に Files.exists() で確認するか、catch で対処する。

現場使用例:CSVの取り込み、ログの記録、設定ファイルの読み込み、レポートの出力。業務システムの多くはファイルを介してデータをやり取りする

import java.io.*;
import java.nio.file.*;
import java.util.*;

// ① 書き込む(上書き)
Path path = Path.of("data.txt");
Files.writeString(path, "1行目\n2行目\n");

// ② 追記する
Files.writeString(path, "3行目\n", StandardOpenOption.APPEND);

// ③ 全体を読む
String all = Files.readString(path);

// ④ 行ごとに読む(List で返る)
List<String> lines = Files.readAllLines(path);
for (String line : lines) {
    System.out.println(line);
}

// ⑤ 存在確認と削除
Files.exists(path);            // true / false
Files.deleteIfExists(path);    // あれば削除

// ⑥ ⭐ try-with-resources(自動で閉じる)
try (BufferedWriter w = Files.newBufferedWriter(Path.of("out.txt"))) {
    w.write("大量のデータを書くとき向き");
    w.newLine();
}   // ← ここで自動的に閉じられる

// ⑦ 例外への対処は必須
try {
    String text = Files.readString(Path.of("nothing.txt"));
} catch (NoSuchFileException e) {
    System.out.println("ファイルがありません");
} catch (IOException e) {
    System.out.println("読み込みに失敗しました");
}

// ⑧ CSVの処理(定番パターン)
for (String line : Files.readAllLines(Path.of("data.csv"))) {
    String[] parts = line.split(",");
    String name = parts[0];
    int price = Integer.parseInt(parts[1]);
}

3基本ドリル(10問)

JV14-D01 ファイル test.txt に「こんにちは」と書き込み、読み返して出力せよ。 コーディング★☆☆無料
期待される結果

出力 == こんにちは

ヒント

Files.writeString と Files.readString を使う。main に throws IOException を付ける。

模範解答
import java.io.*;
import java.nio.file.*;

public class Main {
    public static void main(String[] args) throws IOException {
        Path path = Path.of("test.txt");

        Files.writeString(path, "こんにちは");

        System.out.println(Files.readString(path));

        Files.deleteIfExists(path);
    }
}
解説

書いたものがファイルに残る。プログラムを終了しても消えないので、次回起動時に読み込める。

JV14-D02 ファイル操作のメソッドを呼ぶとき必要なのはどれか。
A. 何も不要 B. IOException への対処 C. static の宣言 D. final の宣言
選択★☆☆無料
期待される結果

解答 == B

ヒント

ファイル操作は失敗する可能性がある。

模範解答
B
解説

try-catch で囲むか throws を宣言する。Javaは「失敗しうる操作」への対処を強制するので、書き忘れるとコンパイルが通らない。

JV14-D03 3行のテキストを書き込み、行ごとに読んで行数を出力せよ。 コーディング★☆☆無料
期待される結果

出力 == 3

ヒント

Files.readAllLines は List を返す。size() で行数が取れる。

模範解答
import java.io.*;
import java.nio.file.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws IOException {
        Path path = Path.of("lines.txt");

        Files.writeString(path, "1行目\n2行目\n3行目\n");

        List<String> lines = Files.readAllLines(path);
        System.out.println(lines.size());

        Files.deleteIfExists(path);
    }
}
解説

readAllLines は改行で分割して List にする。CSVやログの処理では、行単位で扱うことがほとんど。

JV14-D04 ファイルのパスを作るコードを完成させよ。 穴埋め★☆☆無料
コード
import java.io.*;
import java.nio.file.*;

public class Main {
    public static void main(String[] args) throws IOException {
        Path path = Path.____("sample.txt");

        Files.writeString(path, "OK");
        System.out.println(Files.readString(path));
        Files.deleteIfExists(path);
    }
}
期待される結果

出力 == OK

ヒント

「〜の」を意味する2文字のメソッド。

模範解答
of
解説

Path.of が現代的な書き方。古いコードでは new File("…") を見かけるが、新規なら Path を使う。

JV14-D05 Files.writeString を同じファイルに2回実行するとどうなるか。
A. 追記される B. 上書きされる C. エラー D. 2つのファイルができる
選択★☆☆無料
期待される結果

解答 == B

ヒント

既定の動作は上書き。

模範解答
B
解説

前の内容が消える。追記したいなら StandardOpenOption.APPEND を第3引数に渡す。

JV14-D06 ファイルに追記せよ(最初に2行書き、後から1行追記して、合計3行になることを確認)。 コーディング★★☆広告解放
期待される結果

出力 == 3

ヒント

StandardOpenOption.APPEND を第3引数に渡す。

模範解答
import java.io.*;
import java.nio.file.*;

public class Main {
    public static void main(String[] args) throws IOException {
        Path path = Path.of("append.txt");

        Files.writeString(path, "1行目\n2行目\n");
        Files.writeString(path, "3行目\n", StandardOpenOption.APPEND);

        System.out.println(Files.readAllLines(path).size());

        Files.deleteIfExists(path);
    }
}
解説

ログの記録では追記が基本。上書きしてしまうと、過去の記録がすべて失われる。

JV14-D07 ファイルの存在を確認するコードを完成させよ。 穴埋め★★☆広告解放
コード
import java.io.*;
import java.nio.file.*;

public class Main {
    public static void main(String[] args) throws IOException {
        Path path = Path.of("check.txt");
        Files.writeString(path, "test");

        System.out.println(Files.____(path));

        Files.deleteIfExists(path);
    }
}
期待される結果

出力 == true

ヒント

「存在する」を意味する6文字のメソッド。

模範解答
exists
解説

読む前に確認すれば例外を避けられる。ただし確認と読み込みの間にファイルが消える可能性もあるので、catch も併用するのが確実。

JV14-D08 try-with-resources の利点はどれか。
A. 速くなる B. 自動でリソースを閉じてくれる C. 例外が出ない D. メモリを使わない
選択★★☆広告解放
期待される結果

解答 == B

ヒント

finally で close を書く手間が省ける。

模範解答
B
解説

正常終了でも例外発生でも確実に閉じられる。閉じ忘れるとファイルがロックされたままになり、他の処理が失敗する。

JV14-D09 存在しないファイルを読もうとして例外を捕まえ、「ファイルがありません」と出力せよ。 コーディング★★☆広告解放
期待される結果

出力 == ファイルがありません

ヒント

NoSuchFileException を catch する。

模範解答
import java.io.*;
import java.nio.file.*;

public class Main {
    public static void main(String[] args) {
        try {
            Files.readString(Path.of("nothing_xyz.txt"));
        } catch (NoSuchFileException e) {
            System.out.println("ファイルがありません");
        } catch (IOException e) {
            System.out.println("読み込み失敗");
        }
    }
}
解説

ファイルが無いのは「よくあること」。初回起動時は設定ファイルが存在しないので、この対処は必須になる。

JV14-D10 try-with-resources で BufferedWriter を使い、1行書き込んで読み返せ。 コーディング★★☆広告解放
期待される結果

出力 == 自動で閉じる

ヒント

try (BufferedWriter w = Files.newBufferedWriter(path)) { ... } と書く。

模範解答
import java.io.*;
import java.nio.file.*;

public class Main {
    public static void main(String[] args) throws IOException {
        Path path = Path.of("writer.txt");

        try (BufferedWriter w = Files.newBufferedWriter(path)) {
            w.write("自動で閉じる");
        }

        System.out.println(Files.readString(path));

        Files.deleteIfExists(path);
    }
}
解説

カッコを抜けた時点で自動的に閉じられるfinally { w.close(); } を書く必要がなく、閉じ忘れも起きない。

4実践シナリオ(5問)

JV14-S01 【CSVの読み込み】ノートPC,128000,5 形式の2行を書き込み、読み込んで在庫総額を計算せよ(ノートPC/128000/5、マウス/3200/42)。 コーディング★★☆広告解放
期待される結果

出力 == 774400

ヒント

split(",") で分割し、parseInt で数値に変換する。

模範解答
import java.io.*;
import java.nio.file.*;

public class Main {
    public static void main(String[] args) throws IOException {
        Path path = Path.of("stock.csv");

        Files.writeString(path, "ノートPC,128000,5\nマウス,3200,42\n");

        int total = 0;
        for (String line : Files.readAllLines(path)) {
            String[] parts = line.split(",");
            total += Integer.parseInt(parts[1]) * Integer.parseInt(parts[2]);
        }

        System.out.println(total);

        Files.deleteIfExists(path);
    }
}
解説

CSVの取り込みはこの形が基本。実務では業務システム間のデータ連携で頻繁に使われる。

JV14-S02 【ログの記録】ファイルに3回追記し(「処理1」「処理2」「処理3」)、全行を読んで出力せよ。 コーディング★★☆広告解放
期待される結果

出力3行

ヒント

APPEND オプションで繰り返し追記する。

模範解答
import java.io.*;
import java.nio.file.*;

public class Main {
    public static void main(String[] args) throws IOException {
        Path path = Path.of("log.txt");

        Files.writeString(path, "");

        for (int i = 1; i <= 3; i++) {
            Files.writeString(path, "処理" + i + "\n",
                    StandardOpenOption.APPEND);
        }

        for (String line : Files.readAllLines(path)) {
            System.out.println(line);
        }

        Files.deleteIfExists(path);
    }
}
解説

最初に空で書いてファイルを初期化している。APPEND だけだと、前回実行時のログが残ったまま追記されてしまう。

JV14-S03 【存在確認つき読み込み】ファイルがある場合と無い場合の両方を処理せよ(ある場合は内容、無い場合は「未作成」と出力・2行)。 コーディング★★☆広告解放
期待される結果

出力2行。データあり / 未作成

ヒント

Files.exists で分岐する。

模範解答
import java.io.*;
import java.nio.file.*;

public class Main {
    public static void main(String[] args) throws IOException {
        Path exist = Path.of("exist.txt");
        Path notExist = Path.of("not_exist_xyz.txt");

        Files.writeString(exist, "データあり");

        System.out.println(Files.exists(exist)
                ? Files.readString(exist) : "未作成");
        System.out.println(Files.exists(notExist)
                ? Files.readString(notExist) : "未作成");

        Files.deleteIfExists(exist);
    }
}
解説

初回起動時はファイルが無いのが普通。「無ければ既定値を使う」という処理が、設定ファイルの読み込みでは定番になる。

JV14-S04 【集計してファイル出力】CSVを読み込み、集計結果を別のファイルに書き出して読み返せ(在庫総額を「在庫総額:774,400円」の形式で保存)。 コーディング★★★広告解放
期待される結果

出力 == 在庫総額:774,400円

ヒント

読み込んで計算し、結果を writeString で別ファイルに書く。

模範解答
import java.io.*;
import java.nio.file.*;

public class Main {
    public static void main(String[] args) throws IOException {
        Path input = Path.of("in.csv");
        Path output = Path.of("report.txt");

        Files.writeString(input, "ノートPC,128000,5\nマウス,3200,42\n");

        int total = 0;
        for (String line : Files.readAllLines(input)) {
            String[] parts = line.split(",");
            total += Integer.parseInt(parts[1]) * Integer.parseInt(parts[2]);
        }

        Files.writeString(output,
                "在庫総額:" + String.format("%,d", total) + "円");

        System.out.println(Files.readString(output));

        Files.deleteIfExists(input);
        Files.deleteIfExists(output);
    }
}
解説

読み込み → 加工 → 書き出しがバッチ処理の基本形。夜間に大量のデータを処理するシステムは、この流れで動いている。

JV14-S05 【不正データのスキップ】数値でない行を含むCSVを読み込み、変換できる行だけ集計せよ(3行中1行が不正、合計131200)。 コーディング★★★広告解放
期待される結果

出力 == 131200

ヒント

行ごとに try-catch し、失敗したら continue する(JV13の応用)。

模範解答
import java.io.*;
import java.nio.file.*;

public class Main {
    public static void main(String[] args) throws IOException {
        Path path = Path.of("mixed.csv");

        Files.writeString(path, "128000\nabc\n3200\n");

        int total = 0;
        for (String line : Files.readAllLines(path)) {
            try {
                total += Integer.parseInt(line.trim());
            } catch (NumberFormatException e) {
                continue;
            }
        }

        System.out.println(total);

        Files.deleteIfExists(path);
    }
}
解説

1行の不正で全体を止めない。実際のデータには空行や見出し行が混ざることが多いので、この対処は実務で必須になる。

5仕上げ課題

JV14-FINAL 【在庫データの取り込みとレポート出力】ファイル入出力と例外処理を組み合わせよ。

入力ファイル stock.csv(プログラム内で作成)
ノートPC,128000,5
マウス,3200,42
不正行,abc,10
モニター,45000,0
キーボード,8500,18


処理
① CSVを読み込み、数値変換に失敗した行はスキップ(件数を数える)
② 各商品を「ノートPC:640,000円(残りわずか)」の形式で出力
 ・在庫0なら「品切れ」、10未満なら「残りわずか」、それ以外「在庫あり」
③ 在庫総額を計算
結果を report.txt に書き出し、読み返して出力
⑤ 最後に作成したファイルを削除

期待される出力(7行)
ノートPC:640,000円(残りわずか)
マウス:134,400円(在庫あり)
モニター:0円(品切れ)
キーボード:153,000円(在庫あり)
---
取込4件 / 除外1件
在庫総額:927,400円


※ 最後の2行は report.txt から読み返した内容とする
総合★★★広告解放
期待される結果

出力7行が完全一致

ヒント

行ごとに try-catch して NumberFormatException をスキップする。レポートは StringBuilder か文字列連結で組み立て、writeString で保存してから readString で読み返す。

模範解答
import java.io.*;
import java.nio.file.*;

public class Main {

    static String label(int stock) {
        if (stock == 0) return "品切れ";
        if (stock < 10) return "残りわずか";
        return "在庫あり";
    }

    public static void main(String[] args) throws IOException {
        Path input = Path.of("stock.csv");
        Path output = Path.of("report.txt");

        Files.writeString(input,
                "ノートPC,128000,5\n"
                + "マウス,3200,42\n"
                + "不正行,abc,10\n"
                + "モニター,45000,0\n"
                + "キーボード,8500,18\n");

        int total = 0;
        int ok = 0;
        int ng = 0;

        for (String line : Files.readAllLines(input)) {
            String[] parts = line.split(",");

            int price;
            int stock;
            try {
                price = Integer.parseInt(parts[1].trim());
                stock = Integer.parseInt(parts[2].trim());
            } catch (NumberFormatException e) {
                ng++;
                continue;
            }

            int value = price * stock;
            total += value;
            ok++;

            System.out.println(parts[0] + ":"
                    + String.format("%,d", value) + "円(" + label(stock) + ")");
        }

        String report = "取込" + ok + "件 / 除外" + ng + "件\n"
                + "在庫総額:" + String.format("%,d", total) + "円";

        Files.writeString(output, report);

        System.out.println("---");
        System.out.println(Files.readString(output));

        Files.deleteIfExists(input);
        Files.deleteIfExists(output);
    }
}
解説

このプログラムは、実務のバッチ処理そのものだ。ファイルを読み、不正データを除外しながら集計し、結果をレポートとして書き出す——夜間に動く業務システムの多くが、この構造をしている。

不正行の扱いが最も重要だ。「abc」を数値に変換できないからといって処理全体を止めてしまえば、4件の正常なデータも失われる。かといって黙って無視すると、なぜ件数が合わないのか誰にも分からない。スキップしつつ件数を記録する——この折衷案が、実務では最も現実的な対処になる。

parts[1].trim()trim() も見逃せない。CSVは人間が編集することも多く、カンマの後ろに空白が入っているのは日常茶飯事だ。JV03で学んだこの処理が、ここで効いてくる。

そして結果をファイルに書き出している点。画面に出力するだけなら、プログラムが終わった瞬間に消える。ファイルに残せば、翌朝担当者が確認できるし、過去の記録と比較することもできる。

ただし今回のコードには課題もある。parts[1] と書いているが、もし列が2つしかない行があれば範囲外エラーで落ちる。実務ではここも検証が必要になる——外部から来るデータは、あらゆる想定外を含んでいると考えるべきだ。

次章ではジェネリクスを学ぶ。List<String><> が何なのか、その仕組みを理解する。