この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:5
ページ更新者:guest
更新日時:2026-06-11 07:12:00

タイトル: ファイル入出力
SEOタイトル: Java ファイル入出力の完全ガイド(NIO.2 / Files / Stream / try-with-resources)

この記事の要点
  • Java 11+: 一発で読み書きできる Files.readString(path) / Files.writeString(path, str) を最優先
  • 行リストFiles.readAllLines / Files.writeAllLines大ファイルFiles.lines で Stream 化
  • Path / Paths: Paths.get("dir", "file.txt") でプラットフォーム非依存のパス構築
  • try-with-resources 必須: InputStream / Reader は自動 close
  • 文字コードは必ず明示: StandardCharsets.UTF_8。省略するとプラットフォーム既定で文字化け

結論: 用途別の推奨 API

やりたいこと推奨 APIJava 要件
テキスト全体を 1 文字列で読むFiles.readString(path)11+
テキスト全体を 1 文字列で書くFiles.writeString(path, str)11+
行ごとのリストで読むFiles.readAllLines(path, UTF_8)7+
行ごとのリストで書くFiles.write(path, lines, UTF_8)7+
巨大ファイルを 1 行ずつ Stream 処理Files.lines(path, UTF_8)8+
バイナリ全体Files.readAllBytes / Files.write7+
ファイルコピーFiles.copy(src, dst)7+

Java 11+ : 最も簡単な読み書き

import java.nio.file.*;
import java.nio.charset.StandardCharsets;

// テキストを 1 行で読み込む
String text = Files.readString(Paths.get("input.txt"));
// 文字コード指定 (デフォルトは UTF-8)
String text2 = Files.readString(Paths.get("input.txt"), StandardCharsets.UTF_8);

// テキストを 1 行で書き出す
Files.writeString(Paths.get("output.txt"), "Hello, World!");

// 上書きせず追記
Files.writeString(Paths.get("log.txt"), "new line\n",
    StandardOpenOption.APPEND, StandardOpenOption.CREATE);

行リストとして読み書き (Java 7+)

import java.nio.file.*;
import java.nio.charset.StandardCharsets;
import java.util.List;

// 全行をリストで読み込み
List<String> lines = Files.readAllLines(
    Paths.get("data.csv"), StandardCharsets.UTF_8);

for (String line : lines) {
    String[] cols = line.split(",");
    System.out.println(cols[0] + " : " + cols[1]);
}

// リストをファイルに書き出し
List<String> output = List.of("line1", "line2", "line3");
Files.write(Paths.get("output.txt"), output, StandardCharsets.UTF_8);

// 注意: readAllLines は全行をメモリに乗せる
// → 数百 MB 以上のファイルは Files.lines を使う

大ファイル: Files.lines で Stream 処理

import java.nio.file.*;
import java.util.stream.Stream;

// try-with-resources で Stream を必ず close
try (Stream<String> stream = Files.lines(
        Paths.get("bigfile.log"), StandardCharsets.UTF_8)) {

    long errorCount = stream
        .filter(l -> l.contains("ERROR"))
        .count();

    System.out.println("Errors: " + errorCount);
}

// 集計
try (Stream<String> stream = Files.lines(Paths.get("sales.csv"))) {
    double total = stream
        .skip(1)                                       // ヘッダー除外
        .mapToDouble(l -> Double.parseDouble(l.split(",")[2]))
        .sum();
    System.out.println("Total: " + total);
}

Path / Paths でパス構築

import java.nio.file.*;

// 絶対パス / 相対パス
Path p1 = Paths.get(&quot;/home/user/data.txt&quot;);
Path p2 = Paths.get(&quot;data&quot;, &quot;in&quot;, &quot;users.csv&quot;);          // OS の区切り文字で連結

// Java 11+ Path.of (同じ意味だが直感的)
Path p3 = Path.of(&quot;config&quot;, &quot;app.yml&quot;);

// パス操作
Path p = Paths.get(&quot;/var/log/app/error.log&quot;);
p.getFileName();     // error.log
p.getParent();       // /var/log/app
p.getRoot();         // /
p.toAbsolutePath();  // 絶対パス化
p.normalize();       // ../ や ./ を解決

// 存在確認 / メタ情報
Files.exists(p);
Files.isDirectory(p);
Files.isRegularFile(p);
Files.size(p);                                          // バイト数
Files.getLastModifiedTime(p);

レガシー API: Reader / Writer + try-with-resources

細かい制御が必要な場合は BufferedReader / BufferedWriter を使います。必ず try-with-resources で自動 close:

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;

// 行ごとに読み込み (メモリ効率良)
try (BufferedReader br = Files.newBufferedReader(
        Paths.get(&quot;input.txt&quot;), StandardCharsets.UTF_8)) {
    String line;
    while ((line = br.readLine()) != null) {
        // 処理
    }
}

// 書き込み
try (BufferedWriter bw = Files.newBufferedWriter(
        Paths.get(&quot;output.txt&quot;), StandardCharsets.UTF_8,
        StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
    bw.write(&quot;line 1&quot;);
    bw.newLine();
    bw.write(&quot;line 2&quot;);
}

バイナリ入出力

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

// 小〜中サイズ: 全バイト読み込み
byte[] data = Files.readAllBytes(Paths.get(&quot;image.png&quot;));
Files.write(Paths.get(&quot;copy.png&quot;), data);

// 大きいファイル: ストリームでチャンク読み込み
try (InputStream in = Files.newInputStream(Paths.get(&quot;big.bin&quot;));
     OutputStream out = Files.newOutputStream(Paths.get(&quot;copy.bin&quot;))) {
    byte[] buf = new byte[8192];
    int n;
    while ((n = in.read(buf)) != -1) {
        out.write(buf, 0, n);
    }
}

// Java 9+: 標準で transferTo
try (InputStream in = Files.newInputStream(Paths.get(&quot;big.bin&quot;));
     OutputStream out = Files.newOutputStream(Paths.get(&quot;copy.bin&quot;))) {
    in.transferTo(out);                                // 一発でコピー
}

文字コードの落とし穴

文字コードを省略するとプラットフォーム既定(Windows なら MS932/CP932、Linux は UTF-8)が使われます。Linux で動いていた処理が Windows で文字化けする典型例。必ず明示してください:

import java.nio.charset.StandardCharsets;

// ❌ 文字コード未指定 → プラットフォーム依存
String t = Files.readString(p);                        // OK だが既定 UTF-8 (Java 18+ から)

// ❌ FileReader は古い API でデフォルト依存
BufferedReader br = new BufferedReader(new FileReader(&quot;a.txt&quot;));

// ✅ 明示
BufferedReader br = Files.newBufferedReader(p, StandardCharsets.UTF_8);
String t = Files.readString(p, StandardCharsets.UTF_8);

// Shift_JIS のファイルを読む
String t = Files.readString(p, java.nio.charset.Charset.forName(&quot;Shift_JIS&quot;));

ファイル操作 (コピー / 移動 / 削除)

import java.nio.file.*;
import static java.nio.file.StandardCopyOption.*;

Path src = Paths.get("a.txt");
Path dst = Paths.get("b.txt");

// コピー (既存なら上書き)
Files.copy(src, dst, REPLACE_EXISTING);

// 移動 (リネーム含む)
Files.move(src, dst, REPLACE_EXISTING, ATOMIC_MOVE);

// 削除 (存在しないとエラー)
Files.delete(src);

// 存在チェック付き削除
Files.deleteIfExists(src);

// ディレクトリ作成
Files.createDirectories(Paths.get("dir/sub/nest"));   // 中間ディレクトリも作成

// ディレクトリ内のファイル列挙
try (Stream<Path> s = Files.list(Paths.get("/var/log"))) {
    s.filter(Files::isRegularFile)
     .filter(p -> p.toString().endsWith(".log"))
     .forEach(System.out::println);
}

// 再帰列挙
try (Stream<Path> s = Files.walk(Paths.get("/var/log"))) {
    s.filter(Files::isRegularFile).forEach(System.out::println);
}

FAQ

Q: FileNotFoundExceptionNoSuchFileException の違い?
A: 前者は旧 java.io 系、後者は新 java.nio.file 系の例外。Files API は NoSuchFileException をスロー。

Q: 改行コード (CRLF / LF) を制御したい
A: BufferedWriter.newLine() は OS 依存。明示的に bw.write(&quot;\n&quot;) と書く、または Files.writeString で改行込みの文字列を渡す。

Q: ファイルロックは?
A: FileChannel.tryLock() でアドバイザリロック。同一 JVM 内の並行制御には ReentrantLock 等を併用。