F-03a: java.io によるファイル操作(ストリーム・バイト・文字)
Java の伝統的なファイル操作API java.io を使ったテキスト・バイナリファイルの読み書きを解説します。 レガシーシステムでは現在もよく使われるパターンです。 テキスト処理では UTF-8 の正しい指定方法、バイナリコピーでのバッファリング、File クラスによるファイル情報取得を確認しましょう。
いつ使うか
- Java 7 以前のレガシーコードを読んだり改修するとき
- バイナリファイル(画像・PDF・ZIPなど)を読み書きするとき
- 追記モードでログファイルに書き込みたいとき
Fileクラスでファイルの存在確認・サイズ取得・権限確認をするとき
java.io の主要クラス構成
| クラス | 種別 | 用途 |
|---|---|---|
| FileInputStream / FileOutputStream | バイトストリーム | バイナリファイルの読み書き |
| InputStreamReader / OutputStreamWriter | 文字変換 | バイト→文字変換(文字コード指定) |
| BufferedReader / BufferedWriter | バッファリング | 行単位の読み書き・性能向上 |
| File | ファイル情報 | 存在確認・サイズ・更新日時・一覧取得 |
サンプルコード
Java 8 では FileReader や FileWriter は文字コードを指定できないため、InputStreamReader / OutputStreamWriter でラップして StandardCharsets.UTF_8 を指定します。これが java.io でのUTF-8対応の標準パターンです。
よくあるミス・注意点
⚠️ FileReader / FileWriter は文字コードを指定できない
new FileReader(file) は JVM のデフォルト文字コードを使います。Windows では Shift_JIS、Linux では UTF-8 になることが多く、 環境依存の文字化けが発生します。 必ず new InputStreamReader(new FileInputStream(path), StandardCharsets.UTF_8) のように文字コードを明示してください。
⚠️ try-with-resources を使わないとリソースリークが起きる
FileInputStream などのストリームは必ずtry (var in = new FileInputStream(...)) { } の形で使い、close() を確実に呼んでください。 例外が発生した場合でも try-with-resources ならリソースが自動でクローズされます。
⚠️ BufferedReader なしで1文字ずつ読むと遅い
InputStreamReader を直接使って read() を呼ぶと、1文字ずつシステムコールが発生して非常に遅くなります。 必ず BufferedReader でラップしてバッファリングを有効にしてください。
テストする観点
- 書き込んだ内容と読み込んだ内容が一致すること
- 日本語(UTF-8)が文字化けせずに読み書きできること
- 追記モードで書き込んだ場合、既存の内容が保持されること
- 空のファイルを読み込んでも例外が発生せず空リストが返ること(境界値)
- 存在しないファイルパスを読み込んだとき FileNotFoundException がスローされること(異常系)
- バイナリコピーでコピー元とコピー先のファイルサイズが一致すること