概要
業務システムでは、ログの出力、バッチ処理の中間ファイル生成、他システムとの連携ファイル作成など、テキストファイルの読み書きを避けて通れません。Java の java.io パッケージには BufferedReader や BufferedWriter といった基本的なクラスが揃っていますが、文字コードの指定を忘れて文字化けを起こしたり、close 漏れでファイルが壊れたりといったトラブルが後を絶ちません。この記事では、UTF-8 を明示した安全な入出力パターンを整理し、追記モード、バイナリコピー、ファイルの存在確認やサイズ取得までを実務で再利用できる形にまとめます。
使いどころ
バッチ処理の実行ログを日付ごとのテキストファイルに出力する
外部システムから受け取ったテキストファイルを1行ずつ読み込んでDB登録する
帳票データを一時ファイルに書き出し、後続の帳票生成プロセスに渡す
コード例
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.BufferedWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.io.File;
import java.io.IOException;
public class FileIoBasics {
/** テキストファイルを UTF-8 で1行ずつ読み込む */
public static List<String> readLines(String filePath) throws IOException {
var lines = new ArrayList<String>();
try (var reader = new BufferedReader(
new InputStreamReader(
new FileInputStream(filePath), StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
lines.add(line);
}
}
return lines;
}
/** テキストファイルに UTF-8 で書き込む */
public static void writeLines(String filePath, List<String> lines) throws IOException {
try (var writer = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(filePath), StandardCharsets.UTF_8))) {
for (var line : lines) {
writer.write(line);
writer.newLine();
}
}
}
/** 追記モードで1行追加 */
public static void appendLine(String filePath, String line) throws IOException {
try (var writer = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(filePath, true), StandardCharsets.UTF_8))) {
writer.write(line);
writer.newLine();
}
}
public static void main(String[] args) throws IOException {
var path = System.getProperty("java.io.tmpdir") + "/sample.txt";
writeLines(path, List.of("1行目: Hello", "2行目: ファイルI/O", "3行目: UTF-8"));
System.out.println("書き込み完了: " + path);
var lines = readLines(path);
lines.forEach(l -> System.out.println(" " + l));
appendLine(path, "4行目: 追記");
System.out.println("追記後: " + readLines(path).size() + "行");
new File(path).delete();
}
}Version Coverage
var による型推論で記述量が減る。java.io の API 自体に変更はないが、List.of() との組み合わせで簡潔に書ける。
// Java 17: var で型推論、List.of() で簡潔に
var reader = new BufferedReader(
new InputStreamReader(
new FileInputStream(path), StandardCharsets.UTF_8));
writeLines(path, List.of("1行目", "2行目", "3行目"));Library Comparison
注意点
FileReader/FileWriter はデフォルトでプラットフォームのエンコーディングを使うため、環境によって文字化けする。必ず InputStreamReader + StandardCharsets.UTF_8 で文字コードを明示すること。
try-with-resources を使わないと、例外発生時にストリームが close されずファイルが中途半端な状態になる。
FileOutputStream の append フラグ(第2引数 true)を指定し忘れると、既存ファイルの内容が上書きで消える。
大容量ファイルを List に全行読み込むとメモリを圧迫する。数十万行を超える場合はストリーム処理を検討すること。
FAQ
FileReader は Java 11 以降で文字コード指定のコンストラクタが追加されましたが、Java 8 との互換性を考えると InputStreamReader + StandardCharsets.UTF_8 が無難です。
新規コードでは Files を推奨します。既存コードが java.io ベースなら無理に書き換える必要はありません。
8KB(8192バイト)が一般的です。大容量ファイルなら 64KB〜1MB に増やすとスループットが向上する場合があります。