Javaアプリケーションの開発において、CSV(Comma Separated Values)ファイルの読み込みは、データ移行、マスタデータの取り込み、他システムとの連携など、非常に頻繁に発生するタスクの一つです。

CSVは単純なテキスト形式でありながら、実装方法を誤るとエスケープ処理や改行コード、文字コードの問題でバグを誘発しやすいという側面を持っています。

本記事では、Javaの標準機能を用いた基本的な読み込み方法から、実務で推奨される強力な外部ライブラリ(Apache Commons CSV、OpenCSV、Jacksonなど)の使い方まで、エンジニアが現場で即座に活用できる実装例を交えて詳しく解説します。

プロジェクトの規模や要件に最適な手法を選択するための比較ガイドとしてお役立てください。

Java標準機能によるCSV読み込み

外部ライブラリを導入できない制約がある場合や、極めて単純なCSV構造を扱う場合には、Javaの標準APIを使用します。

主に BufferedReader クラスや Scanner クラス、あるいはJava 8以降で導入された java.nio.file.Files を活用するのが一般的です。

BufferedReaderとString.splitを使用した方法

最も古典的かつ軽量な手法が、 BufferedReader で一行ずつ読み込み、 String.split(",") で分割する方法です。

Java
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class StandardCsvReader {
    public static void main(String[] args) {
        String filePath = "data.csv";
        // try-with-resourcesを使用して自動的にクローズする
        try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
            String line;
            while ((line = br.readLine()) != null) {
                // カンマで分割。第2引数に-1を指定すると末尾の空要素も保持される
                String[] values = line.split(",", -1);
                
                // データの処理(ここでは出力のみ)
                for (String value : values) {
                    System.out.print(value + " | ");
                }
                System.out.println();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
実行結果
ID | 名前 | メールアドレス | 
1 | 山田太郎 | yamada@example.com | 
2 | 佐藤花子 | sato@example.jp |

この手法のメリットは、追加の依存関係が一切不要である点です。

しかし、致命的な弱点があります。

それは、「値の中にカンマが含まれている場合(例: “Tokyo, Japan”)」や「値の中に改行が含まれている場合」を正しく処理できないという点です。

RFC 4180というCSVの仕様に厳密に準拠する必要がある現場では、この方法は推奨されません。

Files.linesを使用したモダンな書き方

Java 8以降であれば、 java.nio.file.Files を用いることで、より簡潔にStream APIを活用した記述が可能です。

Java
import java.nio.file.Files;
import java.nio.file.Paths;
import java.io.IOException;
import java.util.stream.Stream;

public class ModernStandardReader {
    public static void main(String[] args) {
        String filePath = "data.csv";

        try (Stream<String> lines = Files.lines(Paths.get(filePath))) {
            lines.map(line -> line.split(",", -1))
                 .forEach(values -> {
                     System.out.println("処理中: " + values[0]);
                 });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

この方法はコードが非常にスッキリしますが、 BufferedReader と同様に複雑なエスケープルールには対応していないため、用途は限定的です。

外部ライブラリを利用すべき理由

実務プロジェクトにおいて、標準機能だけでCSVを処理することは稀です。

その理由は、CSVが「単純に見えて奥が深い」フォーマットだからです。

ダブルクォートのハンドリング

値が " で囲まれている場合や、値の中に " 自体が含まれる(エスケープされている)場合の処理が標準の split では困難です。

改行を含むデータ

セル内に改行コードが含まれる場合、行単位の読み込み(readLine)ではデータが分断されてしまいます。

型変換の自動化

文字列として読み込んだ後、 intLocalDate などの型に変換する手間をライブラリが肩代わりしてくれます。

保守性

独自の実装はバグの温床になりがちですが、実績のあるライブラリはエッジケースを考慮した堅牢な設計になっています。

ここからは、Javaでよく使われる3つの主要ライブラリについて解説します。

Apache Commons CSVによる実装

Apache Commons CSV は、最も汎用性が高く、軽量なライブラリです。

特定の仕様(RFC 4180やExcel形式など)に合わせたフォーマット設定が容易なのが特徴です。

ライブラリの導入 (Maven)

XML
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-csv</artifactId>
    <version>1.10.0</version>
</dependency>

実装例

ヘッダー行を自動認識し、列名でデータにアクセスする例を紹介します。

Java
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;

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

public class ApacheCommonsCsvExample {
    public static void main(String[] args) {
        String filePath = "data.csv";
        
        try (Reader in = new FileReader(filePath)) {
            // ヘッダーを自動取得する設定でパース
            CSVFormat format = CSVFormat.DEFAULT.builder()
                    .setHeader()
                    .setSkipHeaderRecord(true)
                    .build();

            CSVParser parser = format.parse(in);

            for (CSVRecord record : parser) {
                // 列名(ヘッダー名)で値を取得できる
                String id = record.get("ID");
                String name = record.get("名前");
                String email = record.get("メールアドレス");

                System.out.println(id + ": " + name + " (" + email + ")");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Apache Commons CSVは、「シンプルかつ確実にCSVをパースしたい」という場合に最適です。

メモリ消費も比較的少なく、大規模なファイル処理にも適しています。

OpenCSVによるJava Beanへのマッピング

OpenCSV は、読み込んだCSVデータを直接Javaのオブジェクト(POJO)に変換する「マッピング機能」が非常に強力なライブラリです。

ライブラリの導入 (Maven)

XML
<dependency>
    <groupId>com.opencsv</groupId>
    <artifactId>opencsv</artifactId>
    <version>5.9</version>
</dependency>

実装例

まずは、CSVの各列に対応するJavaクラスを定義します。

アノテーションを使用することで、CSVのヘッダー名とフィールドを紐付けます。

Java
import com.opencsv.bean.CsvBindByName;

public class UserBean {
    @CsvBindByName(column = "ID")
    private int id;

    @CsvBindByName(column = "名前")
    private String name;

    @CsvBindByName(column = "メールアドレス")
    private String email;

    // Getter, Setterは省略
}

次に、このBeanを使って読み込みを行います。

Java
import com.opencsv.bean.CsvToBeanBuilder;
import java.io.FileReader;
import java.util.List;

public class OpenCsvExample {
    public static void main(String[] args) {
        String filePath = "data.csv";

        try (FileReader reader = new FileReader(filePath)) {
            List<UserBean> users = new CsvToBeanBuilder<UserBean>(reader)
                    .withType(UserBean.class)
                    .build()
                    .parse();

            for (UserBean user : users) {
                System.out.println(user.getName() + "さんをオブジェクトとして処理中");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

OpenCSVは、「CSVデータをJavaオブジェクトとして扱い、ビジネスロジックに流し込みたい」というシーンで圧倒的な生産性を発揮します。

ただし、リフレクションを多用するため、数百万行といった超巨大なファイルを処理する際はパフォーマンスとメモリ使用量に注意が必要です。

Jackson Dataformat CSVによる高速処理

JSON処理で有名なJacksonライブラリの拡張版である Jackson Dataformat CSV は、非常に高速な処理能力を誇ります。

既存のプロジェクトでJackson(JSON)を使用している場合、学習コストを抑えて導入できます。

ライブラリの導入 (Maven)

XML
<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-csv</artifactId>
    <version>2.15.2</version>
</dependency>

実装例

Jacksonでは CsvMapper を使用して読み込みを行います。

Java
import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;

import java.io.File;
import java.util.Map;

public class JacksonCsvExample {
    public static void main(String[] args) {
        try {
            CsvMapper mapper = new CsvMapper();
            // ヘッダーありのスキーマを設定
            CsvSchema schema = CsvSchema.emptySchema().withHeader();

            File csvFile = new File("data.csv");
            MappingIterator<Map<String, String>> it = mapper
                    .readerFor(Map.class)
                    .with(schema)
                    .readValues(csvFile);

            while (it.hasNext()) {
                Map<String, String> row = it.next();
                System.out.println("名前: " + row.get("名前"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Jacksonは、パフォーマンスが最優先されるWebAPIのデータインポート処理などにおいて強力な選択肢となります。

実装方法の比較まとめ

各手法の特徴を以下の表にまとめました。

用途に合わせて最適なものを選択してください。

手法推奨される用途メリットデメリット
標準API (split)依存関係を追加できない簡易的なツール追加ライブラリ不要。軽量。エスケープや改行に未対応。
Apache Commons CSV一般的なビジネスアプリケーション安定性抜群。RFC 4180に完全準拠。オブジェクトへの自動変換は弱い。
OpenCSVオブジェクト指向な開発、データ登録Beanマッピングが非常に強力。巨大ファイルの処理時にメモリを消費しやすい。
Jackson CSVパフォーマンス重視、JSONと共通化読み込み速度が非常に速い。スキーマ定義の概念が少し独特。

実務で役立つTips:文字コードとBOMの扱い

CSV読み込みで最も多いトラブルの一つが、「文字化け」です。

特にWindowsのExcelで作成されたCSVは、文字コードが Shift_JIS (Windows-31J) であることが多いです。

また、UTF-8であっても BOM(Byte Order Mark) が付与されている場合があり、これが原因で先頭列のヘッダー名が正しく認識されないことがあります。

文字コードを指定して読み込む方法

Java 11以降では、 FileReader に直接文字コードを指定できます。

Java
import java.nio.charset.Charset;
// ...中略...
try (FileReader fr = new FileReader("data.csv", Charset.forName("Windows-31J"))) {
    // このReaderを各ライブラリに渡す
}

BOMを除去する場合

Apache Commons IOなどのライブラリに含まれる BOMInputStream を使用するか、読み込みの最初の数バイトをスキップする処理が必要になる場合があります。

ライブラリによってはBOMを自動で無視するオプションも存在するため、ドキュメントを確認しましょう。

まとめ

JavaでCSVを読み込む方法は多岐にわたりますが、現在の開発シーンにおいては、自作のパースロジックを書くことは避け、信頼性の高いライブラリを使用するのが鉄則です。

  • 単純なパースなら Apache Commons CSV
  • Java Beanへの変換が必要なら OpenCSV
  • 実行速度を極限まで追求するなら Jackson Dataformat CSV

これらを適切に使い分けることで、CSV処理に伴うバグを未然に防ぎ、保守性の高いコードを実現できます。

また、実装時には必ず「文字コード」と「例外処理(ファイル不在やフォーマット不正)」の考慮を忘れないようにしましょう。

本記事が、JavaにおけるCSV読み込み実装の指針となれば幸いです。