(更新: 2026.03.21)

CSV一括インポート機能の実装で詰まった点

CSV一括インポート機能の実装で詰まった点

求人AIツールにCSV一括インポート機能を実装した。

求人サイトから数百件の求人原稿をエクスポートして、まとめてインポート→AIで改善→再エクスポート、という運用を想定している。

実装自体はシンプルだったけど、実運用で詰まったポイントがいくつかあった。

詰まったポイント1: 文字コード問題

日本のExcelからエクスポートされたCSVは、Shift_JISであることが多い。

ブラウザのFileReaderはデフォルトでUTF-8として読み込むので、文字化けが発生する。

解決策

const reader = new FileReader();
reader.readAsText(file, 'Shift_JIS'); // エンコーディング指定

でも、ユーザーが「UTF-8か Shift_JIS か」を意識するのは無理。

最終的には自動判定を実装した:

async function detectEncoding(file: File): Promise<string> {
  const buffer = await file.arrayBuffer();
  const uint8 = new Uint8Array(buffer);

  // BOMチェック
  if (uint8[0] === 0xEF && uint8[1] === 0xBB && uint8[2] === 0xBF) {
    return 'UTF-8';
  }

  // Shift_JIS判定(簡易版)
  // 実際にはライブラリ使う方が確実
  return 'Shift_JIS';
}

詰まったポイント2: カラム名のバラつき

求人サイトごとにCSVのカラム名が違う:
– 「仕事内容」「業務内容」「職務内容」
– 「給与」「月給」「賃金」

解決策

カラムマッピング機能を実装。

インポート時に「このカラムは何に対応しますか?」とユーザーに選ばせる。

<select>
  <option value="job_description">仕事内容</option>
  <option value="salary">給与</option>
  <option value="location">勤務地</option>
</select>

よくあるパターンは自動マッピングで埋めて、不明な列だけユーザーに確認させる。

詰まったポイント3: 大量データの処理

1000件のCSVをインポートすると、ブラウザが固まる

解決策

バッチ処理APIを別途実装し、サーバー側で並列処理する仕組みにした。

// src/app/api/batch-import/route.ts
export async function POST(req: Request) {
  const { csvData } = await req.json();

  // 100件ずつバッチ処理
  for (let i = 0; i < csvData.length; i += 100) {
    const batch = csvData.slice(i, i + 100);
    await processBatch(batch);
  }
}

フロントエンドはプログレスバーを表示するだけ。

まとめ

CSV処理は「動けばいい」と思いがちだが、実運用では細かい問題が山積み

  • 文字コード自動判定
  • カラムマッピング
  • 大量データ対応

この3つを押さえておけば、ユーザーに優しいCSVインポート機能が作れる。

タグ: #開発実績 #エラー解決 #CSV処理