Javaでファイルを読み込む方法は複数ありますが、実務で使うのは主に3つです。BufferedReaderで1行ずつ読む方法、Filesクラスで一括読み込みする方法、そしてScannerで区切り文字ごとに解析する方法――それぞれ得意な場面が異なります。
この記事では、10年以上の業務経験をもとに、3つの方法の使い分けからCSV読み込み・大容量ファイル対応・文字コード指定まで、コピペで動くサンプルコード付きで解説します。try-with-resourcesを使ったエラー処理のベストプラクティスも紹介するので、ファイル読み込みに関する疑問はこの1記事で解決できます。
Javaファイル読み込みの基本3つの方法

Javaでファイル読み込みを行うには、いくつかのクラスを組み合わせて使います。ここでは、最も基本的でよく使われる3つのアプローチを紹介します。それぞれの特徴を理解して、状況に応じて使い分けられるようになりましょう。
Fileクラスを使った基本的な扱い方
まず基本となるのがjava.io.Fileクラスです。注意点として、Fileクラス自体にファイルを読み込む機能はありません。
Fileクラスは、ファイルやディレクトリのパスを抽象的に表現するためのものです。ファイルが存在するかどうかを確認したり、ファイル名を取得したりする際に使います。ファイル操作の「窓口」と考えるとわかりやすいでしょう。
import java.io.File;
public class FileExample {
public static void main(String[] args) {
// ファイルのパスを指定してFileオブジェクトを作成
File file = new File("sample.txt");
// ファイルの存在確認
if (file.exists()) {
System.out.println("ファイルは存在します。");
// ファイルの絶対パスを取得
System.out.println("パス: " + file.getAbsolutePath());
// ファイル名を取得
System.out.println("ファイル名: " + file.getName());
} else {
System.out.println("ファイルが見つかりません。");
}
}
}このコードは、sample.txtというファイルが存在するかどうかをチェックするだけです。実際の読み込みは、このFileオブジェクトを他のクラス(BufferedReaderなど)と組み合わせて行います。
BufferedReaderを使った行ごとの読み込み方法
テキストファイルを1行ずつ読み込んで処理したい場合に最もよく使われるのがBufferedReaderクラスです。
BufferedReaderは、文字をバッファリングしながら読み込むため、効率的に処理できます。readLine()メソッドを使うと、1行ずつ文字列として簡単に取得できるのが大きな特徴です。
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class BufferedReaderExample {
public static void main(String[] args) {
File file = new File("sample.txt");
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
// 1行ずつ読み込み、行がなくなるまでループ
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}この例ではFileReaderと組み合わせています。FileReaderがファイルから文字を読み込み、それをBufferedReaderが効率化して1行ずつ提供するイメージです。大量の行があるファイルを扱う場合に非常に有効なファイル読み込みの方法です。
私自身、業務で数十万行のアクセスログを解析するバッチ処理を書いた際に、BufferedReaderの安定性に助けられました。メモリ消費が一定のまま処理が進むので、本番環境でも安心して使えます。
Scannerを使った簡単な入力処理
Scannerクラスは、コンソールからの入力受付によく使われますが、ファイルの読み込みにも利用できます。
Scannerの便利な点は、スペースや改行などの区切り文字を指定して、単語ごとにデータを読み込めることです。また、nextInt()やnextDouble()といったメソッドを使えば、数値を直接読み取れるため、データ処理が簡単になります。
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class ScannerExample {
public static void main(String[] args) {
File file = new File("sample.txt");
try (Scanner scanner = new Scanner(file)) {
// ファイルの最後まで単語ごとに読み込む
while (scanner.hasNext()) {
String word = scanner.next();
System.out.println(word);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}簡単なテキストデータや、スペース区切りのデータを手軽に扱いたい場合にはScannerが便利です。
ファイル読み込み方法の比較と使い分け

ここまで紹介した基本的な方法には、それぞれ得意なことと不得意なことがあります。ここでは、それぞれの違いや、よりモダンな書き方について見ていきましょう。
BufferedReaderとScannerの違い
BufferedReaderとScannerはどちらもよく使われるため、どちらを選ぶべきか迷うかもしれません。主な違いはパフォーマンスと機能性です。
| 項目 | BufferedReader | Scanner |
| 主な目的 | 1行ずつの高速な読み込み | 区切り文字を使った解析的な読み込み |
| パフォーマンス | 高速。バッファリングにより効率が良い。 | 比較的低速。正規表現による解析処理のため。 |
| 機能性 | readLine()による行単位の読み込みが基本。 | next(), nextInt()などデータ型に合わせた多彩な読み込みが可能。 |
| スレッドセーフ | スレッドセーフ | スレッドセーフではない |
単純にテキストファイルを1行ずつ読み込みたいだけであればBufferedReaderを、スペース区切りのデータや数値を直接扱いたい場合はScannerを選ぶと良いでしょう。パフォーマンスが重要視される大規模なデータ処理では、BufferedReaderの使用が推奨されます。
Filesクラス(Java 7以降)の活用
Java 7で導入されたNIO.2(New I/O 2)のFilesクラスを使うと、ファイル読み込みをさらに簡潔に記述できます。2026年現在のLTSであるJava 21でも引き続き推奨されるAPIで、これから学ぶならこの方法を最優先で覚えましょう。これまでのBufferedReaderなどを使った書き方よりも、はるかに少ないコード量で済むのが最大のメリットです。
例えば、ファイルの内容をすべて一度に読み込んで文字列にする場合、Files.readString()を使えばたった1行です。
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class FilesExample {
public static void main(String[] args) {
Path path = Paths.get("sample.txt");
try {
// ファイルの全行をリストとして読み込む (Java 8+)
// List<String> lines = Files.readAllLines(path);
// System.out.println(lines);
// ファイルの全内容を1つの文字列として読み込む (Java 11+)
String content = Files.readString(path);
System.out.println(content);
} catch (IOException e) {
e.printStackTrace();
}
}
}小さな設定ファイルなどを読み込む際には、このFilesクラスを使う方法が最も手軽で間違いがありません。ただし、巨大なファイルを一括で読み込むとメモリを大量に消費するため、注意が必要です。
文字コード(エンコーディング)への注意点
Windowsで作成したテキストファイルをMacやLinuxで開くと文字化けすることがあるように、Javaのファイル読み込みでも文字コードは非常に重要な問題です。
Java 17以前では、特に指定しない場合、OSのデフォルト文字コードが使われていました。しかしJava 18以降、デフォルト文字コードはOSに関係なくUTF-8に統一されています。Java 17以前の環境やShift_JISファイルを扱う場合は、明示的に文字コードを指定する必要があります。
筆者の経験では、文字コード問題は「開発環境では正常に動くが本番で文字化けする」という形で発覚するケースが大半です。開発端末がMac(UTF-8)で本番がWindows Server(Shift_JIS)だった場合に頻発します。読み込むファイルの文字コードが分かっている場合は、必ず明示的に指定しましょう。
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
public class CharsetExample {
public static void main(String[] args) {
// Shift_JISでエンコードされたファイルを読み込む例
try (BufferedReader br = new BufferedReader(
new InputStreamReader(
new FileInputStream("sample_sjis.txt"), StandardCharsets.UTF_8))) { // ここではUTF-8を指定
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}InputStreamReaderを使うと、FileInputStreamで読み込んだバイトデータを、指定した文字コードで文字に変換できます。2026年現在、新規プロジェクトではUTF-8が事実上の標準です。ただし、官公庁系システムや銀行系レガシーではShift_JISが残っていることもあるため、この方法は覚えておくと役立ちます。
実践的なファイル読み込みサンプルコード

ここからは、より具体的なシナリオを想定したファイル読み込みサンプルコードを見ていきます。
テキストファイルを一括で読み込む
設定ファイルなど、数KB程度の小さなファイルであれば、中身を一度にすべてメモリに読み込んでしまうのが最も簡単です。前述のFiles.readString()が最適です。
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class ReadAllText {
public static void main(String[] args) {
Path path = Path.of("config.txt");
try {
String configContent = Files.readString(path);
System.out.println("--- 設定ファイルの内容 ---");
System.out.println(configContent);
} catch (IOException e) {
System.err.println("ファイルの読み込みに失敗しました: " + e.getMessage());
}
}
}この方法なら、面倒なループ処理やリソースのクローズ処理を気にする必要がありません。
CSVファイルを読み込んで処理する
カンマ区切りのCSVファイルは、データ交換のフォーマットとして頻繁に使われます。BufferedReaderで1行ずつ読み込み、Stringクラスのsplit()メソッドでカンマを基準に分割するのが基本的な処理方法です。
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class CsvReader {
public static void main(String[] args) {
String csvFile = "users.csv";
String line;
try (BufferedReader br = new BufferedReader(new FileReader(csvFile))) {
// ヘッダー行を読み飛ばす場合
// br.readLine();
while ((line = br.readLine()) != null) {
String[] user = line.split(",");
System.out.println("ID: " + user[0] + ", 名前: " + user[1] + ", メール: " + user[2]);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
users.csvファイルを1行ずつ読み込み、各行をカンマで分割してユーザー情報を表示します。本格的なCSV処理では、データ内にカンマが含まれるケースなどを考慮したOpenCSVやApache Commons CSVなどのライブラリを使うのが一般的ですが、簡単なものであればこの方法で対応できます。
実務では、CSVファイルのデータ内にカンマやダブルクォートが含まれるケースが想像以上に多いです。特に顧客名や住所フィールドで問題が発生しやすいため、本番データを扱うなら早い段階でライブラリの導入を検討してください。
大容量ファイルを効率的に扱う
数GBにもなるような大容量のログファイルなどを扱う場合、ファイル全体をメモリに読み込むのは現実的ではありません。OutOfMemoryErrorという致命的なエラーが発生してしまいます。
このようなケースでは、ストリーム処理が必須です。ストリーム処理とは、データを少しずつ読み込みながら処理を進める方式です。BufferedReaderのreadLine()ループや、Java 8から導入されたFiles.lines()メソッドがこれにあたります。Java 21でも変わらず推奨される書き方です。
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;
public class LargeFileReader {
public static void main(String[] args) {
Path path = Path.of("large_log_file.log");
// try-with-resourcesでStreamを自動的にクローズする
try (Stream<String> lines = Files.lines(path)) {
// "ERROR"という単語を含む行だけをカウントする
long errorCount = lines.filter(line -> line.contains("ERROR")).count();
System.out.println("エラー行数: " + errorCount);
} catch (IOException e) {
e.printStackTrace();
}
}
}Files.lines()は、ファイルを行ストリームとして扱えるようにします。メモリ消費を最小限に抑えながら、フィルタリングや集計といった高度なデータ処理を簡潔に記述できるのです。
大容量ファイルを扱う際のファイル読み込みでは、この方法が現在のベストプラクティスと言えるでしょう。
resourcesフォルダからファイルを読み込む(クラスパス)
Mavenや Gradleプロジェクトでは、設定ファイルやテンプレートをsrc/main/resourcesに配置するのが一般的です。このresourcesフォルダ内のファイルは、Fileクラスで直接パスを指定しても読み込めません。代わりにgetResourceAsStream()を使います。
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
public class ResourceReader {
public static void main(String[] args) {
// クラスパス上の "config.properties" を読み込む
try (InputStream is = ResourceReader.class.getResourceAsStream("/config.properties");
BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException | NullPointerException e) {
System.err.println("リソースの読み込みに失敗しました: " + e.getMessage());
}
}
}パスの先頭に/を付けるとクラスパスのルートからの絶対パスになります。/なしだと呼び出し元クラスのパッケージからの相対パスです。getResourceAsStream()は見つからない場合にnullを返すため、NullPointerExceptionへの対策も忘れずに入れておきましょう。
JARファイルにパッケージした後もこの方法なら正しくリソースを読み込めるため、プロジェクト内の設定ファイルやテンプレートにはgetResourceAsStream()を使うのが鉄則です。
ファイル読み込み時のエラー処理

ファイル操作にはエラーがつきものです。ファイルが存在しなかったり、読み込み権限がなかったりと、予期せぬ事態は常に起こり得ます。堅牢なプログラムを作るためには、適切なエラー処理が不可欠です。
FileNotFoundExceptionへの対応
FileNotFoundExceptionは、その名の通り「指定されたパスにファイルが見つからない」場合に発生する、最も代表的な例外です。
FileNotFoundExceptionが発生するということは、プログラムの前提が崩れている状態です。ユーザーにファイルパスを再入力させたり、処理を中断してエラーメッセージを表示したりといった対応が必要になります。
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class FileNotFoundHandler {
public static void main(String[] args) {
File file = new File("non_existent_file.txt");
try {
Scanner scanner = new Scanner(file);
// ... 読み込み処理 ...
} catch (FileNotFoundException e) {
System.err.println("エラー: ファイルが見つかりません。");
System.err.println("パスを確認してください: " + file.getAbsolutePath());
}
}
}catchブロックでこの例外を捕まえ、利用者に分かりやすいメッセージを出すことが重要です。
IOExceptionの基本的なハンドリング
IOExceptionは、I/O操作全般で発生する可能性のある、より広範な例外です。FileNotFoundExceptionもIOExceptionの一種です。
ディスクの故障やネットワークの切断で読み込みが中断された場合にもIOExceptionが発生します。ファイル操作を行うコードは、必ずIOExceptionを処理するtry-catchブロックで囲んでください。
try-with-resourcesを使った安全な書き方
Java 7から導入されたtry-with-resources文は、ファイル読み込みにおけるエラー処理とリソース管理を劇的に改善しました。
古いコードでは、finallyブロックでclose()メソッドを呼び出し、リソースを明示的に閉じる必要がありました。このclose()処理を忘れると、ファイルハンドルが解放されずに残り、システムの不安定化を招く原因となります。
try-with-resourcesを使えば、tryブロックを抜ける際に自動的にリソースをクローズしてくれます。
// 悪い例(Java 6以前の古い書き方)
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("sample.txt"));
// ... 読み込み処理 ...
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close(); // 手動でクローズする必要がある
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 良い例(Java 7以降のモダンな書き方)
try (BufferedReader br = new BufferedReader(new FileReader("sample.txt"))) {
// ... 読み込み処理 ...
// tryブロックを抜ける際に自動でbr.close()が呼ばれる
} catch (IOException e) {
e.printStackTrace();
}コードがシンプルになるだけでなく、close()の呼び忘れも防げるため、現在のJavaではtry-with-resources文を使うのが常識です。特別な理由がない限り、必ずこの書き方を採用してください。実際のコードレビューでも、try-with-resourcesを使っていないコードは即座に指摘対象になります。レガシーコードのリファクタリング案件でも、最初に手をつけるべき改善箇所です。
よくある質問(FAQ)
Javaでファイルを読み込む最も簡単な方法は?
Java 11以降であればFiles.readString(Path)が最も簡単です。1行で全内容を文字列として取得できます。ただし、ファイルサイズが大きい場合はメモリを圧迫するため、数KB〜数MB程度の設定ファイルや小さなテキストファイル向けです。
BufferedReaderとScannerはどちらを使うべき?
テキストファイルを1行ずつ処理するならBufferedReaderが高速で推奨です。スペース区切りのデータや数値を直接読み取りたい場合はScannerが便利です。パフォーマンスが重要な大規模処理ではBufferedReader一択です。
大容量ファイルを読み込むとOutOfMemoryErrorが出るのはなぜ?
Files.readAllLines()やFiles.readString()はファイル全体をメモリに展開するため、数GB規模のファイルではヒープ領域が不足します。Files.lines()やBufferedReaderのループで1行ずつ処理するストリーム方式に切り替えてください。
まとめ
今回は、Javaにおけるファイル読み込みの基本から実践的なテクニック、そして重要なエラー処理までを解説しました。最後に、ポイントを振り返ってみましょう。
目的別に使い分ける読み込み方法
- 小さなファイルを一括で読みたい ->
Files.readString()やFiles.readAllLines()が手軽で最適。 - ファイルを1行ずつ処理したい ->
BufferedReaderを使うのが基本。パフォーマンスも良い。 - 大容量ファイルを効率的に扱いたい ->
Files.lines()を使ったストリーム処理が必須。メモリを圧迫しない。 - スペース区切りなど簡単なデータを解析したい ->
Scannerが便利。 - クラスパス上のリソースを読みたい ->
getResourceAsStream()を使えばJAR内でも動作する。