😊

【Java】ファイルの読み書きまとめ

に公開

ファイルの読み書きについて

  • Java では、java.io や java.nio パッケージを使ってファイルの読み書きを行うことができます。
  • ファイル操作には主に 「文字(テキスト)データの処理」 と 「バイナリデータ(画像や音声など)の処理」 があります。

文字データの読み書き

文字データ(テキストファイル)の読み書きには、以下のクラスを使用します。

書き込み

  • FileWriter:文字をファイルに書き込む
  • BufferedWriter:バッファを使用するので、効率よく書き込むことができる

読み込み

  • FileReader:ファイルを文字単位で読み込む
  • BufferedReader:バッファを使用するので、効率よく読み込むことができる

文字の書き込み(基本的な方法)

  • シンプルな構文でファイルに文字を書き込める。
  • FileWriter(String, true) で追記モードが可能。
  • 文字を直接ディスクに書き込むため 遅い(バッファリングがない)
package fileTest;

import java.io.FileWriter;
import java.io.IOException;

public class FileWriteExample {
	public static void main(String[] args) {
		//ファイルを開く
		//new FileWriter("test.txt", true) とすると追記モードになる
		try (FileWriter fw = new FileWriter("test.txt")) { 
			//ファイルに書き込む
			fw.write("こんにちは、Javaファイルの書き込み!\n");
			fw.write("2行目のテスト");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

test.txt
こんにちは、Javaファイルの書き込み!
2行目のテスト

java.nio.file.Filesを使用した場合

  • シンプルなコードでファイル書き込みが可能。
  • リストの内容を 一括で書き込みできる。
  • Files.write() は 全データを一括で書き込むのでメモリの消費が大きい
  • ディスク容量不足などで途中で異常が発生した場合にデータの一部しか書き込まれない可能性がある
  • 既存の内容を上書きする。追記したい場合はStandardOpenOption.APPENDを- Files.write() の第3引数に指定する
package fileTest;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;

public class FilesWriteExample {
	public static void main(String[] args) {
		try {
			//Files.write() は リスト (List<String>) を渡すと、複数行を書き込める
			//Paths.get("test.txt") でファイルのパスを指定
			Files.write(Paths.get("filesWrite.txt"), Arrays.asList(
					"こんにちは、Javaファイルの書き込み!",
					"2行目のテスト"));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

文字の書き込み(BufferedWriter を使う)

  • バッファリングにより、複数回の書き込みをまとめて処理し 効率が良い。
  • newLine() メソッドで改行が簡単にできる。
  • 大きなファイルを扱うなら、BufferedWriter を使って ストリームで少しずつ書き込む のが良い
  • BufferedWriter を使うために FileWriter が必要(若干コードが長くなる)。
package fileTest;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class BufferedWriteExample {
	public static void main(String[] args) {
		try (BufferedWriter bw = new BufferedWriter(new FileWriter("bufferedWrite.txt"))) {
			bw.write("バッファ付きで書き込み\n");
			bw.write("効率的なファイル書き込み");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

bufferedWrite.txt
バッファ付きで書き込み
効率的なファイル書き込み

文字の書き込み(PrintWriter を使う)

  • println() で簡単に改行できる。
  • printf() でフォーマット出力が可能。
  • BufferedWriter と同様にバッファを持っており、効率的。
  • BufferedWriter に比べて、処理が遅くなることがある。
package fileTest;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class PrintWriteExample {
    public static void main(String[] args) {
        try (PrintWriter pw = new PrintWriter(new FileWriter("printWrite.txt"))) {
            pw.println("PrintWriter を使用して書き込み");
            pw.println(123);  // 数値も直接書ける
            pw.printf("フォーマット出力: %.2f", 3.1415);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

printWrite.txt
PrintWriter を使用して書き込み
123
フォーマット出力: 3.14

文字の読み込み(基本的な方法)

  • シンプルなコードで1文字ずつ読み込める。
  • 1文字ずつしか読めないため、処理が遅い。(BufferedReader を使う方が一般的。)
package fileTest;

import java.io.FileReader;
import java.io.IOException;

public class FileReadExample {
	public static void main(String[] args) {
		//fileRead.txtを開く(ファイルは用意しておく)
		try (FileReader fr = new FileReader("fileRead.txt")) {
			int c;
			while ((c = fr.read()) != -1) { // 1文字ずつ読み込む
				System.out.print((char) c);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

fileRead.txt
こんにちは、Javaファイルの書き込み!
2行目のテスト

<出力例>
こんにちは、Javaファイルの書き込み!
2行目のテスト

java.nio.file.Filesを使用した場合

  • 簡単にファイルを一括読み込みできる。
  • List<String> に変換されるので 処理がしやすい。
  • 大きなファイルには不向き(全データをメモリにロードするため)。
package fileTest;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;

public class FilesReadExample {
	public static void main(String[] args) {
		try {
			//全行をリストに取得
			List<String> lines = Files.readAllLines(Paths.get("filesRead.txt"));
			lines.forEach(System.out::println);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

文字の読み込み(BufferedReader を使う)

  • 1行ずつ読み込めるので、FileReader より高速。
  • バッファリングによって効率的。
  • BufferedReader のインスタンス作成のコードが FileReader より少し長い。
package fileTest;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class BufferedReadExample {
	public static void main(String[] args) {
		//bufferedRead.txtを開く(ファイルは用意しておく)
		try (BufferedReader br = new BufferedReader(new FileReader("bufferedRead.txt"))) {
			String line;
			while ((line = br.readLine()) != null) { // 1行ずつ読み込む
				System.out.println(line);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

bufferedRead.txt
バッファ付きで書き込み
効率的なファイル書き込み

<出力例>
バッファ付きで書き込み
効率的なファイル書き込み

バイナリデータの読み書き

画像・音声・動画などのバイナリデータを扱う場合、InputStream / OutputStream を使用します。

書き込み
FileOutputStream:バイナリデータを書き込む
BufferedOutputStream:バッファを使用するので効率よく書き込む

読み込み
FileInputStream:バイナリデータを読み込む
BufferedInputStream:バッファを使用するので効率よく読み込む

バイナリデータの書き込み(FileOutputStream)

  • 1バイトずつ書き込むので非効率(BufferedOutputStream の方が速い)。
  • テキストファイルには不向き(文字エンコーディングの処理がない)。

例)ファイルに「ABCDE」と書き込む

package fileTest;

import java.io.FileOutputStream;
import java.io.IOException;

public class BinaryWriteExample {
	public static void main(String[] args) {
		byte[] data = { 65, 66, 67, 68, 69 }; // A, B, C, D, E

		try (FileOutputStream fos = new FileOutputStream("binary.dat")) {
			fos.write(data);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

バイナリデータの書き込み(BufferedOutputStream)

  • バッファを使用して 書き込み効率が向上(複数回の書き込みをまとめて処理)。
  • BufferedOutputStream のインスタンス作成が若干面倒。
package fileTest;

import java.io.BufferedOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class BufferedOutputStreamExample {
	public static void main(String[] args) {
		try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bufferedOutputStream.dat"))) {
			//ABCと書き込む
			bos.write(new byte[] { 65, 66, 67 });
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

バイナリデータの読み込み(FileInputStream)

  • 1バイトずつ読むため、処理が遅い。
  • BufferedInputStream の方が効率が良い。
package fileTest;

import java.io.FileInputStream;
import java.io.IOException;

public class BinaryReadExample {
	public static void main(String[] args) {
		try (FileInputStream fis = new FileInputStream("binary.dat")) {
			int byteData;
			while ((byteData = fis.read()) != -1) {
				System.out.print((char) byteData);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

<出力例>
ABCDE

バイナリデータの読み込み(BufferedInputStream)

  • バッファリングにより、FileInputStream より高速。
  • BufferedInputStream を作成する手間がある。
package fileTest;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class BufferedInputStreamExample {
	public static void main(String[] args) {
		try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("bufferedOutputStream.dat"))) {
			int b;
			while ((b = bis.read()) != -1) {
				System.out.print((char) b);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}
}

<出力例>
ABC

まとめ

大きなデータを扱う場合は Buffered 系を、簡単な処理なら Files クラスを活用する

  • 基本的な文字の書き込み → BufferedWriter
  • 簡単な改行やフォーマットが必要 → PrintWriter
  • 基本的な文字の読み込み → BufferedReader
  • バイナリデータの書き込み → BufferedOutputStream
  • バイナリデータの読み込み → BufferedInputStream
  • シンプルなファイル処理がしたい → Files.write() / Files.readAllLines()

Discussion