【JavaScript】FileAPIからCSVを読み込んでみる

html5

CSVファイルとかよく扱ったりすることもありますよね。今回はHTML5から追加されたFilleAPIというのがあって、もともとサーバーにあるファイルを読みにいくのではなく、フォームのアップロードみたいなボタンでCSVファイルを読み込んで出力する時の処理の方法を防備録として残しておく。

実際のサンプル

実際にCSVをアップロードして出力したものになります。

See the Pen javascriptでFileAPIからCSVを読み込んでみる by kiriyama (@kirikirimai) on CodePen.

FileAPIについて

そもそもFileAPIってなんぞや?という方。ネットでたくさん情報があるので、簡単に書くと HTML5 から追加された File API でWebページにユーザーのローカルにあるファイルを直接読み込めるようなりました。方法としては「input」の方法と ドラッグ&ドロップ という方法があります。
今回はinputを使った処理になります。

記述はいたって簡単でhtmlでは下記のように書きます。

HTML



//複数のファイルを処理したい場合は属性にmultipleを設定する


上記のように「type」属性に「file」を指定してあげるだけです。
また複数のファイルを扱いたい場合は属性に「multiple」を記載してあげるだけです。画像を複数枚アップなどに使用できそうです。

プログラムの流れ

HTMLはフォームタイプで「file」を選べばいいので簡単ですが、今度はjavascriptで読み込んだCSVファイルを出力する流れを書いていきます。

1:ボタンを取得してchangeイベントの設定

// 1: ボタンを取得してchangeイベントの設定
var loadBtn = document.querySelector("#loadBtn");
loadBtn.addEventListener("change", upload, false);

まずはファイルを読み込むボタンを「querySelector」でDOM要素を取得して、CSVファイルをアップした時に発生する「change」イベントを設定し、upload関数を実行します。

2:FileAPIがブラウザに対応してるかチェック

function upload(evt) {

// 2:FileAPIがブラウザに対応してるかcheckFileReader関数でチェック
if (!checkFileReader()) {
    alert("エラー:FileAPI非対応のブラウザです。");
   } else {

   //ファイルを読み込む処理
   }
}

function checkFileReader() {
  var isUse = false;
  if (window.File && window.FileReader && window.FileList && window.Blob) {
    isUse = true;
  }
  return isUse;
}

FileAPIがHTML5から追加されたこともあり、念のためブラウザでチェックしておきます。 もし使えるなら「isUse]変数にtrueの値を入れてreturnで返します。」

3: 選択されたファイル情報を取得する

 // 3: 選択されたファイル情報を取得
var file = event.target.files[0]; 
   
//readerオブジェクトを作成
var reader = new FileReader();
    
// ファイル読み取りを実行
 reader.readAsText(file);

ブラウザでFileAPIが使えるなら実際に読み込み処理になります。
まず関数の引数に「event」と引数から「target.files」からアップしたファイルを取得します。filesは配列なので対象ファイルはfiles[0]に格納されています。


この時点ではアップロードされたファイルを取得しただけであってまだ読み込んでません。この後に FileReader オブジェクトの「 readAsText」メソッドを実行することでCSVファイルの読み込み処理が可能になります。
ですので、FileReaderオブジェクトの「reader」を作成し「 readAsText 」メソッドに取得したファイル(file変数)を引き渡します。
*ちなみに画像ファイルを読み込む時には「readAsDataURL」メソッドがありますのでそちらを使用します。

4:CSVファイルを読み込む処理とエラー処理をする

// 3: 選択されたファイル情報を取得
 var file = event.target.files[0];
   
//readerオブジェクトを作成
  var reader = new FileReader();

// ファイル読み取りを実行
reader.readAsText(file);
    
    
// 4:読み込んだCSVファイルを取得
reader.onload = function(event) {

  var result = event.target.result;
  makeCSV(result);

 };
    
//読み込めなかった場合のエラー処理
  reader.onerror = function() {
    alert("エラー:ファイルをロードできません。");
 };

前回でFileReaderオブジェクトの「readAsText」メソッドで読み来むファイルを指定しましたが、「onload」メソッドで読む込む処理とonerrorメソッドで読み込めなかった場合の処理を書いていきます。 まずエラーの場合は上記のように「onerror」メソッド内でアラートを表示しています。

「onload」メソッドでは、FileAPIのchangeメソッドと同様にevent.targetのresultプロパティに読み込まれたCSVファイルのデータが格納されていますので一旦、result変数に入れて、makeCSVメソッドに引き渡します。
*処理が長くなりそうなのでmakeCSVメソッドにしただけです。

5:csvデータを1行ごとに配列にする

//CSVを出力する関数
function makeCSV(csvdata) {

  //5:csvデータを1行ごとに配列にする
  var tmp = csvdata.split("\n");

}
 

さて、CSVファイルを読み込んだら実際に出力までの処理をmakeCSV関数内で処理していきます。まずはCSVデータを1行ごとで管理するために改行コードごとに配列に入れるため。splitメソッドで「\n」としています。
*splitメソッドは指定した文字や正規表現によるで文字列を分割して配列で返すメソッドです
これにより変数tmlに1行ごとのCSVのデータが格納されています。

6:1行のデータから各項目(各列)のデータを取りだし、2次元配列にする


  //csvデータをそのままtableで出力する
  var tabledata = $("#resulttable");
  var htmldata = "";
  
  //6:1行のデータから各項目(各列)のデータを取りだして、2次元配列にする

  //各列を格納する変数
  var data = [];
  for (var i = 0; i < tmp.length; i++) {
    
    //csvの1行のデータを取り出す
    var row_data = tmp[i]; 
    data[i] = row_data.split(","); 

    /* 各行の列のデータを配列にする2次元配列
    data[
          [1列目、2列目、3列目] ←1行目の列の配列 
          [1列目、2列目、3列目] ←2行目の列の配列 
          [1列目、2列目、3列目] ←3行目の列の配列 
        ]
 */
}
    

変数:tabledataはCSVのデータを出力する場所のDOMと変数:htmldataはCSVのデータをtableタグとして出力する為の変数です。

さて、ここからが本題ですが、まず各行の列データを配列として管理する為、変数:dataを用意しておきます。その後にCSVデータの行の長さ分、for文でぶん回します。

  1. tmp[i]として、CSVの1行ごとに変数:row_dataに格納します。
  2. 変数:row_dataにある行から 各列(各項目) のデータをsplitメソッドで「,(カンマ)」区切りで配列でdata[i]に代入することで2次元配列ができます。上記コード内に2次元配列がどうなってるかコメント内に記載しています

7:dataに入ってる 各列(各項目) のデータを個別に出力する為のhtmlデータを作る

 data[i] = row_data.split(","); 

//7:dataに入ってる各列のデータを出力する為のデータを作る
 htmldata += "
"; for (var j = 0; j "; } htmldata += "";

Webページにtableタグとして出力したいのでfor文の中でさらにfor文で回します。まずは、tableタグで出力する為に1回目のfor分は行ごとに処理しているので変数:htmldataをtrの開始タグで「+」で追加しています。
変数:dataに入ってる各列の長さを変数:jとし、各行の 各列(各項目) のデータを出力する必要があるので「data[i][j]」とすることで 、1行ごとの各列(各項目)のデータを出力することができます。

あとは、tableタグで出力したいので 各列(各項目) のデータをtdタグで括り、 各列(各項目) のfor分の処理が終わったら、変数:htmldataにtrの閉じタグを追加してあげることでCSVデータの完成です。

8: データをWebページに出力する


// 8: データをWebページに出力する
  htmldata += "
"; tabledata.append(htmldata);

2つのfor分でCSVデータを出力用に作成し終えたら、実際にWebページに出力します。変数:htmldataにtableの閉じタグを追加してあげます。

後は、jQueryですが、変数:tabledata(#resulttableのDOM)にappendメソッドでhtmldataを追加してあげることでCSVデータがちゃんとWebページに出力されているはずです。

CSVを扱う際の注意点

今回のFileAPIだけでなくともCSVを読み込む方法は他にもありますが、読み込む際の注意点として、CSVファイルの文字コードは「UTF-8」で、「コンマ区切り」にしましょう。どちらも一般的だと思います。

また今回の処理はCSVの「名前」や「メールアドレス」などタイトルの部分もそのまま読み込んですが実際は必要ないことが多いです。その場合は一旦、行ごとで配列に追加した後に配列の最初行・・・つまりタイトルなどの行を配列のメソッドで削除するなどの処理をしたほうがいいでしょう。

またCSVを読みこんで処理をしましたが、画像やテキストファイルをアップしてしまうこともあるかと思います。その際は、FileAPIのchangeメソッド内で、ファイルを取得した際にファイル情報の入ったプロパティが用意されてるんでチェックするといいと思います。下記に記載します。

 // 3: 選択されたファイル情報を取得
var file = event.target.files[0];
var type = file.type; // MIMEタイプ
var size = file.size; // ファイル容量(byte)
var limit = 10000; // byte, 10KB
 
// MIMEタイプの判定
if ( type == 'image/jpeg' ) {
    alert('画像はアップロードできません');
    return;
} 
   
//readerオブジェクトを作成
var reader = new FileReader();
    
// ファイル読み取りを実行
 reader.readAsText(file);