【Java】CSVファイルを読み込む方法|split(“,”)の落とし穴とライブラリの使い分け

JavaでCSVファイルを読み込む基本は「BufferedReader で1行ずつ読み、split(",") でカンマ分割」です。シンプルなCSVならこれで十分ですが、引用符付きのフィールドや末尾の空欄では split(",") が正しく動きません。この記事では基本と、その限界・対処を解説します。

この記事の結論:単純なCSVは BufferedReadersplit(",", -1) で読めます(-1 で末尾の空欄も保持)。日本語はStandardCharsets.UTF_8 を明示引用符内のカンマや改行を含む本格CSVは、自前のsplitではなくOpenCSVなどのライブラリを使います。
スポンサーリンク

基本:BufferedReaderとsplitで読み込む

UTF-8を明示して1行ずつ読み、カンマで分割します。split(",", -1) のように第2引数に -1 を渡すのが重要です(理由は後述)。

CSVを読み込む(UTF-8・末尾空欄保持)
import java.io.*;
import java.nio.charset.StandardCharsets;

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

        try (BufferedReader br = new BufferedReader(
                 new InputStreamReader(
                     new FileInputStream(csvFile), StandardCharsets.UTF_8))) {
            String line;
            boolean isHeader = true;
            while ((line = br.readLine()) != null) {
                if (isHeader) { isHeader = false; continue; } // ヘッダ行をスキップ
                String[] cols = line.split(",", -1); // -1 で末尾の空欄も保持
                System.out.println("名前=" + cols[0] + " 年齢=" + cols[1]);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

注意1:split(“,”) は末尾の空欄を捨てる

意外な落とし穴です。split(",")(第2引数なし)は末尾の空フィールドを削除します。CSVで末尾の列が空のとき、列数が合わなくなり ArrayIndexOutOfBoundsException の原因になります。

末尾の空欄の扱い
String line = "a,b,,";

String[] a = line.split(",");     // ["a", "b"](末尾の空欄2つが消える)
System.out.println(a.length);     // 2

String[] b = line.split(",", -1); // ["a", "b", "", ""](保持される)
System.out.println(b.length);     // 4
CSVの分割では必ず split(",", -1) を使いましょう。空の列が末尾にあると、split(",") では列数が減り、後続の cols[3] のようなアクセスで例外になります。

注意2:引用符付きフィールドはsplitで壊れる

CSVの仕様(RFC 4180)では、フィールドをダブルクオートで囲み、その中にカンマや改行を含められます。このようなCSVを split(",") で分割すると、引用符内のカンマでも区切られてしまいデータが壊れます

splitでは正しく分割できない例
// "Tokyo, Japan" のようにフィールド内にカンマがある
String line = "1,\"Tokyo, Japan\",100";

String[] cols = line.split(",", -1);
// 期待: [1, "Tokyo, Japan", 100](3列)
// 実際: [1, "Tokyo,  Japan",  100](引用符内のカンマで4列に割れて壊れる)
System.out.println(cols.length); // 4(意図とずれる)
引用符・カンマ・改行を含む本格的なCSVは、自前のsplitではなくライブラリを使いましょう。代表的なのは OpenCSVApache Commons CSV です。引用符の処理やエスケープを正しく扱ってくれます。社内データなど「カンマや改行を含まない」と保証できる単純なCSVに限り、splitで十分です。

ライブラリ(OpenCSV)を使う場合

OpenCSVを使うと、引用符付きフィールドも正しく1行ずつ配列で取得できます(Mavenなどで依存を追加して使用します)。

OpenCSVでの読み込み(イメージ)
import com.opencsv.CSVReader;
import java.io.*;
import java.nio.charset.StandardCharsets;

try (CSVReader reader = new CSVReader(
         new InputStreamReader(new FileInputStream("data.csv"), StandardCharsets.UTF_8))) {
    String[] cols;
    while ((cols = reader.readNext()) != null) {
        // 引用符内のカンマも正しく1フィールドとして扱われる
        System.out.println(String.join(" / ", cols));
    }
}
ファイル読み込み全般(文字コードの注意)はファイルを読み込む方法、CSVの書き出しはファイルに書き込む方法文字列をカンマ区切りで結合する方法を参照してください。

よくある質問(FAQ)

Qsplit(“,”)で末尾の列が消えます。
Asplit(",")末尾の空フィールドを削除する仕様だからです。split(",", -1) と第2引数に -1 を渡すと、末尾の空欄も保持されます。
Qフィールド内にカンマがあるCSVが正しく読めません。
Asplit(",") は引用符を解釈しないため、"Tokyo, Japan" のような引用符内のカンマでも区切ってしまい壊れます。OpenCSVやApache Commons CSVなどのライブラリを使ってください。
Q日本語のCSVが文字化けします。
AFileReaderが既定の文字コードで読むためです。InputStreamReaderStandardCharsets.UTF_8 を明示してください(Excel由来のCSVはShift_JISのこともあるので、その場合は "MS932" など)。
Qヘッダ行を飛ばすには?
A最初の1行を読み飛ばすフラグを使うか、readLine() を先に1回呼んでから本処理に入ります。本文のように isHeader フラグで continue する方法が簡単です。

まとめ

JavaでCSVを読み込むポイントを整理します。

  • 単純なCSVは BufferedReadersplit(",", -1)(末尾空欄を保持)
  • 日本語は StandardCharsets.UTF_8 を明示(Excel由来はShift_JISも)
  • 引用符内のカンマ・改行を含むCSVはsplitでは壊れる → OpenCSV等のライブラリ
  • ヘッダ行はフラグや先読みでスキップ

関連として、ファイルを読み込む方法ファイルに書き込む方法文字列をカンマ区切りで結合する方法もあわせて読むと、JavaのファイルI/O・CSV処理に強くなれます。