【JavaScript】ドラッグ&ドロップでCSVファイルを読み込む

#JavaScript
にメンテナンス済み
記事のトップ画像

ブラウザ上にCSVファイルをドラッグ&ドロップして、中身を2次元配列として扱う方法を紹介します。使うのは標準のAPI(Drag and Drop API と FileReader)だけで、ライブラリは不要です。

全体の流れ

  1. ドロップ領域に dragover / drop イベントを登録する
  2. drop イベントの event.dataTransfer.files からファイルを取得する
  3. FileReader でテキストとして読み込む
  4. 改行・カンマで分割して2次元配列にする

ドラッグ&ドロップのイベントを登録する

まず、ファイルをドロップできる領域を取得し、イベントを登録します。

// ドラッグ&ドロップを許可する領域を取得
const dropArea = document.body;

// 対象領域にファイルがドラッグされている間のイベント
dropArea.addEventListener('dragover', (event) => {
  // これを呼ばないと drop イベントが発火しない
  event.preventDefault();

  // ドラッグしているファイルの表示を「コピー」にする
  event.dataTransfer.dropEffect = 'copy';
});

// 対象領域にファイルがドロップされた際のイベント
dropArea.addEventListener('drop', (event) => {
  // ドロップされたファイルをブラウザが開いてしまうのを防ぐ
  event.preventDefault();

  getFiles(event.dataTransfer.files);
});

dragover で preventDefault() を呼ぶのが重要なポイントです。これを忘れると、ドロップしてもブラウザがファイルを開くだけで drop イベントが発火しません。

ドラッグ中に領域のスタイルを変えたい場合は、dragenter / dragleave で CSS クラスを付け外しすると、ユーザーにドロップ可能であることが伝わりやすくなります。

ドロップされた CSV を 2 次元配列に変換する

const getFiles = (files) => {
  for (const file of files) {
    const reader = new FileReader();

    reader.onload = (event) => {
      const text = event.target.result;

      const csv = text
        .split(/\r?\n/)
        .filter((row) => row !== '')
        .map((row) => row.split(','));

      console.log(csv);
    };

    // テキスト形式で読み込む(文字コードの既定値は UTF-8)
    reader.readAsText(file);
  }
};

\r?\n で分割しているのは、Windows で作成した CSV の改行コード(CRLF)にも対応するためです。

注意点

ダブルクォートやセル内のカンマには対応していない

上記の split(',') は単純な分割なので、"東京, 渋谷",100 のようにセルの中にカンマや改行を含む CSV は正しく分解できません。実用的なCSVを扱う場合は、Papa Parse などのパーサーライブラリの利用を検討してください。

文字コード

readAsText は既定で UTF-8 として読み込みます。Excel で保存した Shift_JIS の CSV は文字化けするため、第2引数にエンコーディングを指定します。

reader.readAsText(file, 'Shift_JIS');

ファイルの種類を確認する

あらゆるファイルがドロップされ得るため、必要に応じて拡張子を確認しましょう。

if (!file.name.endsWith('.csv')) continue;