業務で「CSV読み込みユーティリティ」が必要になる理由
CSVは、業務システムで一番よく使われるデータ形式のひとつです。 顧客一覧、売上データ、設定情報、外部ベンダーとの連携ファイル——どれもだいたい CSV です。
そのたびに「行を split して…」「ダブルクォートをどう扱うか…」を毎回手書きしていると、 微妙なバグや仕様差が積み重なって、あとから地獄になります。
だからこそ、「CSV読み込み」をユーティリティとしてきちんと切り出しておくことが、 業務・実務ではかなり重要になります。
ここでは、初心者向けに噛み砕きつつ、実務で通用するレベルまで丁寧に説明します。
CSVの基本ルールをざっくり押さえる
行と列のイメージ
CSVは「行の集まり」であり、 各行は「カンマ区切りの値の集まり」です。
ざっくり言うと、
- 1 行 = 1 レコード
- 1 列 = 1 項目
というイメージです。
しかし、ここで初心者がよくハマるポイントがあります。
カンマそのものを値に含めたい場合
例えば、次のような値を CSV に入れたいとします。
東京都,江戸川区
このまま書くと、カンマで列が分割されてしまいます。 そこで、CSVでは「ダブルクォートで囲む」というルールがあります。
"東京都,江戸川区"
こうすると、カンマは「値の一部」として扱われます。
改行を値に含めたい場合
同じように、改行を含む値もダブルクォートで囲みます。
"1行目
2行目"
このようなルールがあるので、 単純に line.split(",") では正しく CSV を読めません。
シンプルなCSV読み込みユーティリティ(「割り切り版」)
「カンマを含まない」「ダブルクォートを使わない」前提ならこれで十分
まずは、ルールがシンプルな CSV(カンマもダブルクォートも含まない)を読むユーティリティから見てみましょう。
import java.io.IOException;
import java.nio.charset.Charset;
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 SimpleCsvReader {
public static List<String[]> read(Path path, Charset charset) throws IOException {
List<String[]> rows = new ArrayList<>();
for (String line : Files.readAllLines(path, charset)) {
if (line.isEmpty()) {
continue; // 空行はスキップ
}
String[] columns = line.split(",", -1); // -1 で末尾の空列も保持
rows.add(columns);
}
return rows;
}
public static List<String[]> readUtf8(Path path) throws IOException {
return read(path, StandardCharsets.UTF_8);
}
}
Java使い方の例です。
Path path = Path.of("data/simple.csv");
List<String[]> rows = SimpleCsvReader.readUtf8(path);
for (String[] cols : rows) {
System.out.println("1列目: " + cols[0] + ", 2列目: " + cols[1]);
}
Javaここで重要なのは、「split に -1 を渡している」ことです。 split(",", -1) とすると、末尾の空列もきちんと保持されます。
例えば、
コード
a,b,
という行は、["a", "b", ""] になります。
これをしないと、 「最後の列が空のときに列数が減る」という地味なバグが起きます。
ちゃんとしたCSVを読むときの考え方
ダブルクォートとカンマを正しく扱う必要がある
実務では、「カンマを含む値」「改行を含む値」「ダブルクォートを含む値」が普通に出てきます。
CSVの正式ルールでは、次のような扱いになります。
- 値にカンマや改行を含めたいときは、値全体を
"..."で囲む - 値の中に
"を含めたいときは、""と二重に書く
例:
"東京都,江戸川区","彼は""天才""と呼ばれた"
これを自前でパースするのは、初心者にはかなりしんどいです。 実務でも、ここを手書きするのはおすすめしません。
ライブラリを使う、という選択肢
業務では、CSVパーサのライブラリ(OpenCSV など)を使うのが一般的です。 ここではコード詳細には踏み込みませんが、考え方だけ押さえておきます。
- ライブラリは「CSVの正式ルール」をきちんと実装してくれている
- 自前実装よりも、仕様差やバグのリスクが圧倒的に少ない
- ユーティリティは「ライブラリの使い方を隠すラッパー」として設計する
こうしておくと、業務コード側は「CSV読み込みユーティリティを呼ぶだけ」で済み、 CSVの細かい仕様を意識せずに済みます。
CSV読み込みユーティリティで絶対に意識してほしいポイント
文字コードを必ず指定する
CSV読み込みで一番やってはいけないのが、 文字コードを指定せずに new String(bytes) や Files.readAllLines(path) を使うことです。
文字コードを指定しないと、OSやJVMのデフォルトに依存し、 開発環境と本番環境で挙動が変わる原因になります。
業務では、ほぼ常に UTF-8 に統一するのがおすすめです。
Files.readAllLines(path, StandardCharsets.UTF_8);
Javaこのように、必ず Charset を明示してください。
BOM(UTF-8 BOM)の存在を意識する
CSVの先頭に BOM が付いていると、 1 列目の先頭に「見えないゴミ」が混ざり、ヘッダ名が一致しなくなります。
例: 本来 → id,name,email BOM付き → id,name,email
これを防ぐために、 「CSV読み込みユーティリティの中で BOM を除去する」という設計も有効です。
すでに話した BOM除去ユーティリティと組み合わせると、 CSV読み込みがかなり安定します。
行数・列数のチェックを入れる
CSVは「静かに壊れる」ことが多い形式です。 例えば、途中の行だけ列数が違う、 空行が紛れ込んでいる、 ヘッダ行とデータ行の列数が合わない——などです。
ユーティリティ側で次のようなチェックを入れておくと、 業務コードが安心して使えるようになります。
- 1 行目をヘッダとして扱い、列数を基準にする
- 2 行目以降で列数が違う行があればログや例外にする
- 空行はスキップするかどうかを方針として決める
CSV読み込みユーティリティの実務的な使いどころ
外部ベンダーからのデータインポート
外部ベンダーから送られてくる顧客データや売上データは、 ほぼ確実に CSV です。
ここで「毎回その場で CSV を手書きパースする」のではなく、 共通の CSV読み込みユーティリティを通すことで、 文字コード・BOM・列数チェックなどを一括で管理できます。
管理画面からの CSVアップロード
管理画面で「CSVをアップロードして一括登録」という機能を作るとき、 CSV読み込みユーティリティがあるかどうかで、 バグの量と保守性が大きく変わります。
アップロード処理は「ファイルを受け取る」ことに集中し、 中身の解釈はユーティリティに任せる—— この分離ができていると、テストもしやすくなります。
まとめ:CSV読み込みユーティリティで身につけてほしい感覚
CSV読み込みユーティリティは、「業務データを安全に、安定して取り込む」ための入り口です。 そこには、次のような大事な感覚が詰まっています。
文字コード(UTF-8など)を必ず明示して読むこと。 単純な split(",") ではなく、列数や空列の扱いを意識すること。 BOM の存在を前提にし、必要なら除去してから読むこと。 CSVの正式ルール(ダブルクォート・カンマ・改行)を自前で頑張りすぎず、ライブラリ+ユーティリティで包むこと。
もし今、あなたのプロジェクトに「画面ごと・機能ごとにバラバラな CSV読み込みコード」が散らばっているなら、 それを一度「業務用 CSV読み込みユーティリティ」に集約できないか眺めてみてほしいです。
そこから先は、外部データの取り込みが、ぐっと安定していきます。
