本ページはプロモーションが含まれています

Java入門

Javaのファイル読み込み7選|CSV・1行ずつ・大容量まで

CATEGORY
REV.
DRAWN BY
TOM
SHEETS
6枚
Files.read(ファイル読み込み7選)

トム

SESで約8年、環境を変えられないもどかしさの中にいました。32歳で自社開発企業に転職し、今はClaude Codeと自動化で、仕事も時間も組み直している途中です。
・Javaバックエンドエンジニア(Java歴12年以上)
・資格:基本情報技術者/応用情報技術者/Java Silver/Python3エンジニア認定基礎
詳細なプロフィール

𝕏

Javaでファイルを読み込む方法は、目的で決まります。

小さなファイルはFiles.readString()で一括、1行ずつ処理するならBufferedReaderかFiles.lines()、CSVはsplit()か専用ライブラリです。

やりたいこと使うAPI
小さなテキストを丸ごと読むFiles.readString()
1行ずつ読むBufferedReader.readLine()
CSVを読んでListに格納するsplit(",", -1) / OpenCSV / Commons CSV
数GB級の大容量ファイルFiles.lines()
resourcesフォルダのファイルgetResourceAsStream()

値にカンマを含むCSV・数GB級のログ・resourcesフォルダの設定ファイルなど、つまずきやすいケースもコピペで動くサンプルコードで示します。

この記事でわかること

  • File・BufferedReader・Scannerを使ったファイル読み込みの基本3方法
  • BufferedReader・Scanner・Filesクラスの違いと使い分け
  • CSVをListに格納する方法(ヘッダー・空欄・文字コード対策)とOpenCSV・Apache Commons CSVの使い方
  • 大容量ファイル・resourcesフォルダ・プロパティファイル・JSONの読み込みサンプル
  • FileNotFoundException・IOExceptionへの対処とtry-with-resourcesの安全な書き方

PARTS LIST /目次

Javaファイル読み込みの基本3つの方法

Javaのファイル読み込みとは、テキストファイルやCSV・プロパティファイルなどの中身を、プログラムから扱える形に変換する処理のことです。

具体的には、BufferedReaderやFilesクラスといった標準APIのクラスを経由します。

Javaのファイル読み込みは、複数のクラスを組み合わせて使います。まずは基本のFile・BufferedReader・Scannerの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行ずつ読み込む

テキストファイルを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が便利です。

あわせて読む

ファイル読み込み方法の比較と使い分け

どの方法を使うかは、次の順に質問に答えていけば決まります。

読み込み方法の選び方(Q1から順に答える)
QUESTION / 質問
はい
いいえ
Q1. resourcesフォルダ(JAR内)にあるファイル?
getResourceAsStream()Fileクラスでは読めないクラスパス上のファイルも、JARに入れた後まで動作する。見つからないとnullを返す
Q2へ
Q2. CSVファイル?
Q3へ
Q4へ
Q3. 値にカンマ・ダブルクォート・改行が入る?
OpenCSV / Apache Commons CSV引用符付きの値に入ったカンマや改行も正しく分割できる
BufferedReader + split(",", -1)第2引数に-1を渡すと、行末の空欄も空文字として残る
Q4. 数百MB〜GB級の大容量?
Files.lines() / BufferedReader1行ずつ処理するので、ファイル全体をメモリに載せない
Q5へ
Q5. 1行ずつ処理したい?
BufferedReader.readLine()1行ずつ文字列として取得できる定番の方法
Files.readString()Java 11以降、1行で全内容を文字列にできる。大きなファイルには不向き
NOTEQ2で「はい」ならQ3、「いいえ」ならQ4に進みます。大容量のファイルは、Q5まで進まずQ4で1行ずつ読む方法に決まります。

BufferedReaderとScannerの違い

BufferedReaderとScannerはどちらもよく使われるため、どちらを選ぶべきか迷うかもしれません。主な違いはパフォーマンスと機能性です。

項目BufferedReaderScanner
主な目的1行ずつの高速な読み込み区切り文字を使った解析的な読み込み
パフォーマンス高速。バッファリングにより効率が良い。比較的低速。正規表現による解析処理のため。
機能性readLine()による行単位の読み込みが基本。next(), nextInt()などデータ型に合わせた多彩な読み込みが可能。
スレッドセーフスレッドセーフスレッドセーフではない

テキストファイルを1行ずつ読むだけならBufferedReaderを選びます。

スペース区切りのデータや数値を直接扱いたいときはScannerが向いています。

Filesクラス(Java 7以降)の活用

Java 7で導入されたNIO.2(New I/O 2)のFilesクラスを使うと、ファイル読み込みをさらに簡潔に記述できます。

2026年現在の最新LTSはJava 25(2025年9月リリース)です。

Java 21も含め幅広いLTSバージョンで引き続き推奨される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.Charset;

public class CharsetExample {
    public static void main(String[] args) {
        // Shift_JISでエンコードされたファイルを読み込む例(MS932を指定)
        try (BufferedReader br = new BufferedReader(
                new InputStreamReader(
                        new FileInputStream("sample_sjis.txt"), Charset.forName("MS932")))) { // ここでMS932(Shift_JIS系)を指定
            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ファイルを読み込んで処理する|split()とOpenCSVの使い分け

カンマ区切りの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なら、この方法で十分です。

ただし実務のCSVは、顧客名や住所の欄にカンマ・ダブルクォート・改行が入っていることがよくあります。

判断の基準は行数ではなく中身です。値にカンマ・ダブルクォート・改行が入る可能性があるなら、最初からOpenCSVやApache Commons CSVを使いましょう。

あとからカンマ混入のバグを直すより、結果的に手間が少なく済みます。

CSVをListに格納する|ヘッダー・空欄・文字コード対策

読み込んだCSVは、あとで集計や並べ替えをするためにList<String[]>へ格納するのが定番です。

次のコードは、実務でつまずきやすい3点(ヘッダー行・末尾の空欄・文字コード)をまとめて対策しています。

import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;

public class CsvToList {
    public static void main(String[] args) throws IOException {
        Path path = Path.of("users.csv");
        List<String[]> rows = new ArrayList<>();

        // 文字コードを明示する(ExcelのCSVなら Charset.forName("MS932"))
        try (BufferedReader br = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
            String header = br.readLine(); // 1行目(ヘッダー)を読み飛ばす
            String line;
            while ((line = br.readLine()) != null) {
                if (line.isBlank()) {
                    continue; // 空行はスキップ
                }
                // 第2引数に-1を渡すと、末尾の空欄も要素として残る
                rows.add(line.split(",", -1));
            }
        }

        System.out.println("データ件数: " + rows.size());
        for (String[] row : rows) {
            System.out.println("ID: " + row[0] + ", 名前: " + row[1] + ", メール: " + row[2]);
        }
    }
}

split(",")は、行末の空欄を配列から消してしまいます。

メール欄が空の行でrow[2]にアクセスすると、ArrayIndexOutOfBoundsExceptionで止まります。第2引数に-1を渡せば、空欄も空文字として残ります。

String line = "1,山田,";
System.out.println(line.split(",").length);     // 2(末尾の空欄が消える)
System.out.println(line.split(",", -1).length); // 3(空欄も残る)

ExcelでCSV保存したファイルは、文字コードがShift_JIS(WindowsではMS932)のことが多いです。

その場合はStandardCharsets.UTF_8をCharset.forName("MS932")に変えてください(java.nio.charset.Charsetのimportが必要です)。

「CSV UTF-8」形式で保存したファイルは先頭にBOMが付くため、1列目のヘッダー名に見えない文字が混ざる点にも注意しましょう。

OpenCSV・Apache Commons CSVでCSVを読み込む

OpenCSVは、引用符付きフィールド内のカンマや改行を正しく解釈できる専用ライブラリです。

Maven/Gradleに依存関係を追加するだけで使えます。

<!-- pom.xml -->
<dependency>
  <groupId>com.opencsv</groupId>
  <artifactId>opencsv</artifactId>
  <version>5.12.0</version>
</dependency>
import com.opencsv.CSVReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;

public class CsvReaderOpenCSV {
    public static void main(String[] args) throws IOException {
        String path = "users.csv";
        try (CSVReader reader = new CSVReader(new FileReader(path))) {
            List<String[]> lines = reader.readAll();
            for (String[] line : lines) {
                System.out.println("ID: " + line[0] + ", 名前: " + line[1] + ", メール: " + line[2]);
            }
        } catch (com.opencsv.exceptions.CsvException e) {
            e.printStackTrace();
        }
    }
}

reader.readAll()を使えば、カンマや改行が値の中に含まれていても正しく行単位・列単位に分割してくれます。

自前のsplit(",")は手軽な反面、値の中にカンマが1つでも混入すると壊れます。

もう1つの定番がApache Commons CSVです。RFC 4180(CSVの標準仕様)に沿って解析し、ヘッダーの列名で値を取り出せるのが強みです。

<!-- pom.xml -->
<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-csv</artifactId>
  <version>1.14.1</version>
</dependency>
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;

import java.io.IOException;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;

public class CsvReaderCommons {
    public static void main(String[] args) throws IOException {
        // 1行目をヘッダーとして扱い、列名で値を取り出せるようにする
        CSVFormat format = CSVFormat.DEFAULT.builder()
                .setHeader()
                .setSkipHeaderRecord(true)
                .get();

        try (Reader reader = Files.newBufferedReader(Path.of("users.csv"), StandardCharsets.UTF_8);
             CSVParser parser = format.parse(reader)) {
            for (CSVRecord record : parser) {
                System.out.println(record.get("id") + " / " + record.get("name"));
            }
        }
    }
}

record.get("name")のように列名で書けるため、列の順番が変わっても修正が要りません。

列番号で素早く書きたいならOpenCSV、列名で読みやすく書きたいならCommons CSV、と選ぶと迷いません。

大容量ファイルを効率的に扱う

数GBにもなるような大容量のログファイルなどを扱う場合、ファイル全体をメモリに読み込むのは現実的ではありません。

ヒープ領域が足りなくなり、OutOfMemoryErrorでプログラムが停止します。

「まとめて読み込んだ方が効率的なはず」という直感は、データ量が増えるほど裏切られます。

以前、Spring Batchのバッチ処理でchunk sizeを1000件に設定していました。

その結果、本番環境がOutOfMemoryErrorで落ちたことがあります。

原因調査に2時間かかった一方、修正はchunk sizeを100件に下げるだけの5分で完了しました。ファイル読み込みでも構造は同じです。

Files.readAllLines()で「とりあえず全部読む」実装は、開発環境の小さなテストデータでは問題が表面化しません。

本番の大容量ファイルで、初めて牙を剥きます。

あわせて読む

このようなケースでは、ストリーム処理が必須です。ストリーム処理とは、データを少しずつ読み込みながら処理を進める方式です。

BufferedReaderのreadLine()ループや、Java 8から導入されたFiles.lines()メソッドがこれにあたります。

まとめて読む vs 1行ずつ読む(ファイルの大きさとメモリ)
ITEM / 項目
まとめて読む
1行ずつ読む
使うAPI
Files.readAllLines() / readString()
Files.lines() / BufferedReader
メモリ(ヒープ)に載るもの
読んだ全行
処理中の1行だけ処理済みの行はメモリから消える
小さいファイルテスト環境
OK全行を読み込んで完了
OK全行の処理が完了
大きいファイル本番環境
NGヒープが足りず OutOfMemoryError で停止
OKメモリには常に1行だけで完了
NOTE仕組みのイメージです。小さいテストデータでは差が出ず、本番の大容量ファイルで初めて落ちるのがまとめて読む方法の落とし穴です。

2026年現在の最新LTSであるJava 25でも変わらず推奨される書き方です。

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に配置するのが一般的です。

JARにまとめた後は、resourcesフォルダ内のファイルをFileクラスのパスで指定しても読み込めません(IDEから実行する場合はたまたま動くこともあります)。

代わりに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への対策も忘れずに入れておきましょう。

あわせて読む

そのため、プロジェクト内の設定ファイルやテンプレートにはgetResourceAsStream()を使うのが鉄則です。

プロパティファイルを読み込む(Propertiesクラス)

設定値をキーとバリューのペアで管理したい場合は、java.util.Propertiesクラスが便利です。

.properties形式のファイルをload()メソッドに渡すだけで、シンプルな設定管理が実現できます。

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class PropertiesExample {
    public static void main(String[] args) {
        Properties props = new Properties();
        // クラスパス上の config.properties を読み込む
        try (InputStream is = PropertiesExample.class.getResourceAsStream("/config.properties")) {
            props.load(is);
            String dbUrl = props.getProperty("db.url");
            System.out.println("db.url = " + dbUrl);
        } catch (IOException e) {
            System.err.println("プロパティファイルの読み込みに失敗しました: " + e.getMessage());
        }
    }
}

前述のgetResourceAsStream()と組み合わせれば、JARファイルにパッケージされた設定ファイルもそのまま読み込めます。

DB接続情報やAPIキーなど、環境ごとに差し替えたい値を管理する用途でよく使われる方法です。

ここで注意したいのが文字コードです。

Properties#load(InputStream)は、内部でISO-8859-1(Latin-1)としてバイト列を解釈します。

そのため、日本語のコメントや値を含む.propertiesファイルを上記のコードでそのまま読み込むと文字化けします。

日本語を扱う場合は、load(InputStream)ではなくload(Reader)を使います。

Readerには、UTF-8を指定したInputStreamReaderを渡してください。

あわせて読む

JSONファイルを読み込む

JavaにはJSONを解析する標準APIが含まれていないため、JacksonやGsonといった外部ライブラリを使うのが一般的です。

ここでは広く使われているJacksonの例を紹介します。

2025年10月には、groupIdがtools.jackson.coreに変わるJackson 3.0もGAリリースされました。

ただし既存プロジェクトの多くはまだ2.x系のため、ここでは安定した2.x系の書き方を使います。

// build.gradle: implementation 'com.fasterxml.jackson.core:jackson-databind:2.22.2'
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.io.IOException;

public class JsonExample {
    public static void main(String[] args) {
        ObjectMapper mapper = new ObjectMapper();
        try {
            User user = mapper.readValue(new File("user.json"), User.class);
            System.out.println(user.getName());
        } catch (IOException e) {
            System.err.println("JSONの読み込みに失敗しました: " + e.getMessage());
        }
    }
}

readValue()にJSONファイルとマッピング先のクラスを渡すだけで、フィールド名が一致していれば自動的にオブジェクトへ変換してくれます。

Files.readString()で文字列として読み込んでから自前でパースすることも、技術的には可能です。

ただし、ネストしたJSONの扱いが煩雑になるため、実務ではライブラリを使う方法が推奨されます。

あわせて読む

ファイル読み込み時のエラー処理

ファイル操作にはエラーがつきものです。ファイルが存在しなかったり、読み込み権限がなかったりと、予期せぬ事態は常に起こり得ます。

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());
        }
    }
}

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)

Q1. Javaでファイルを読み込む最も簡単な方法は?

A1. Java 11以降であればFiles.readString(Path)が最も簡単です。1行で全内容を文字列として取得できます。ただし、ファイルサイズが大きい場合はメモリを圧迫するため、数KB〜数MB程度の設定ファイルや小さなテキストファイル向けです。

Q2. BufferedReaderとScannerはどちらを使うべき?

A2. テキストファイルを1行ずつ処理するならBufferedReaderが高速で推奨です。スペース区切りのデータや数値を直接読み取りたい場合はScannerが便利です。パフォーマンスが重要な大規模処理ではBufferedReaderかFiles.lines()が向いています。

Q3. 大容量ファイルを読み込むとOutOfMemoryErrorが出るのはなぜ?

A3. Files.readAllLines()やFiles.readString()は、ファイル全体をメモリに展開します。そのため、数GB規模のファイルではヒープ領域が不足します。Files.lines()やBufferedReaderのループで1行ずつ処理するストリーム方式に切り替えてください。

Q4. resourcesフォルダ内のファイルを読み込むにはどうすればいい?

A4. JARにまとめた後は、Fileクラスでパスを指定しても読み込めません。getResourceAsStream()を使い、クラスパス経由でInputStreamとして取得してください。JARファイルにパッケージした後も同じ方法で読み込めます。

Q5. プロパティファイルの日本語が文字化けするのはなぜ?

A5. Properties#load(InputStream)が内部でISO-8859-1(Latin-1)としてバイト列を解釈するためです。日本語を含む場合はload(Reader)にUTF-8指定のInputStreamReaderを渡してください。

Q6. JSONファイルを読み込むのに標準APIだけで足りる?

A6. いいえ、足りません。JavaにはJSON解析の標準APIが含まれていないため、JacksonやGsonなどの外部ライブラリを使うのが一般的です。Files.readString()で読み込んで自前パースすることも技術的には可能ですが、ネストしたJSONでは煩雑になります。

Q7. 文字コードを指定せずにファイルを読み込むとどうなる?

A7. Java 18以降は、OSに関係なくUTF-8として読み込まれます。Shift_JISのファイルは文字化けするため、文字コードを明示してください。

Java 17以前はOSの既定の文字コードが使われるため、Windows(MS932)ではUTF-8のファイルが文字化けします。どのバージョンでもStandardCharsetsで指定しておくのが確実です。

Q8. CSVを読み込んで配列やListに格納するには?

A8. BufferedReaderで1行ずつ読み、line.split(",", -1)で分割した配列をList<String[]>に追加します。第2引数の-1を付けないと、行末の空欄が消えて列数がずれます。値にカンマや改行が入る場合はOpenCSVかApache Commons CSVを使ってください。

Q9. ファイルの途中の行から・指定した行だけ読み込むには?

A9. Files.lines()のskip()とlimit()を組み合わせます。先頭から順に読み飛ばす方式ですが、1行ずつ処理するため大きなファイルでもメモリを圧迫しません。

// 11行目から5行分だけ読む(先頭10行を飛ばす)
try (Stream<String> lines = Files.lines(Path.of("app.log"))) {
    lines.skip(10).limit(5).forEach(System.out::println);
}

まとめ

迷ったら「ファイルの大きさ」と「1行ずつ処理するか」の2点で選べば、ほとんどのケースに対応できます。

目的別に使い分ける読み込み方法

  • 小さなファイルを一括で読みたい -> Files.readString() や Files.readAllLines() が手軽で最適。
  • ファイルを1行ずつ処理したい -> BufferedReader を使うのが基本。パフォーマンスも良い。
  • CSVを読んでListに格納したい -> 単純なCSVは split(",", -1)、値にカンマや改行が入るなら OpenCSV か Apache Commons CSV。
  • 大容量ファイルを効率的に扱いたい -> Files.lines() を使ったストリーム処理が向いている。メモリを圧迫しない。
  • スペース区切りなど簡単なデータを解析したい -> Scanner が便利。
  • クラスパス上のリソースを読みたい -> getResourceAsStream() を使えばJAR内でも動作する。
※本記事のバージョン情報は2026年9月時点のものです(Java 25 LTS・OpenCSV 5.12.0・Apache Commons CSV 1.14.1・Jackson 2.22.2基準)。ライブラリのバージョンは適宜最新のものをご確認ください。
REVISIONS / 改訂履歴
REV.DATE内容
62026-10-15図解を描き直し(図面のデザインにそろえた)
52026-10-04記載内容の事実確認と修正
42026-09-012026年9月時点の情報で全体を見直し(古い記述を2件更新)
32026-08-172026年8月時点の情報で全体を見直し(古い記述を3件更新)
… ほか1回の改訂
12025-10-04初版
NEXT READ本棚から1本

AIで開発を組み直すなら、まずこの5冊から

入門・実践・設計まで、Claude Codeの本をレベル別に5冊選んで比べました。

→ おすすめ5冊を見る

  • この記事を書いた人
  • 最新記事

トム

SESで約8年、環境を変えられないもどかしさの中にいました。32歳で自社開発企業に転職し、今はClaude Codeと自動化で、仕事も時間も組み直している途中です。
・Javaバックエンドエンジニア(Java歴12年以上)
・資格:基本情報技術者/応用情報技術者/Java Silver/Python3エンジニア認定基礎
詳細なプロフィール

𝕏

Java入門