JavaScriptでデータからCSVファイルを生成しダウンロードさせる

いろいろなファイルアイコン(文字)
管理アプリケーションから任意のレコードを選択してボタンを押すと、用途に合わせた情報が抽出されてCSVファイルとしてダウンロード出来る……という要件を満たすために、最初はPHP主体で処理することを考えていたのですが、色々調べてみるとほとんどJavaScriptで出来ることがわかりました。あとで記載する参考リンクの情報を組み合わせるとこんな感じ。






簡単な説明

let bom = new Uint8Array([0xEF, 0xBB, 0xBF]);


CSVで日本語を扱うための準備です。これをやらないとBOMなしのUTF-8になり、Excelで開けません。「Excelなんか使わないけんね」という路線を通したいところですが、残念ながらそうもいかないのでやっておきます。Excelなんか早く捨てれば良いのに。


let data = records.map((record) => record.join('\t')).join('\r\n');


用意してきた配列をCSV用の文字列に加工しています。タブで区切って、改行を挟むという感じですね。


let blob = new Blob([ bom, data ], { 'type' : 'text/csv' });


バイナリデータオブジェクト。古いブラウザでは扱えません。Chrome、Firefox、Edgeは対応しています。Safari、InternetExplorer10/11もたぶん大丈夫。業務で使用しているPCには古いものもあるので一抹の不安はありますが……たぶん大丈夫でしょう……ていうか、「InternetExplorer9で動きません」っていうクレームが入ったら「そんなもん使うな」ぐらい言っても良いと思う。


let downloadLink = document.createElement('a');
downloadLink.download = 'sample.csv';
downloadLink.href = URL.createObjectURL(blob);
downloadLink.dataset.downloadurl = [
   'text/plain',
   downloadLink.download,
   downloadLink.href
].join(':');
downloadLink.click();


ダウンロードリンクを作成し、そのdownload属性にファイル名を指定、クリックするという挙動を再現しています。これをすることでHTMLにリンクパーツがなくても大丈夫。こういうところJavaScriptは素敵ですよね。



応用編

実際の場面では、recordsはバックグラウンドのPHPフレームワークからAjaxを使ってJSON形式で取得します。PHPだけでやるとヘッダやらなんやら処理が意外と煩雑になるんですが(最新のフレームワークは楽なのかな)、これだとデータの受け渡しだけで終わります。ファイル名も取得してもいいかも知れませんね。



参考にさせていただいた記事

JavaScriptでファイルダウンロード処理を実現する – Qiita
jsでダウンロードを実装した話 – Qiita
BOMやBlobを理解してJavaScriptでCSVを出力する – Qiita
Blob – Web API | MDN


ありがとうございます。