クライアント側でCSV生成してダウンロードさせる

追記:
Safariも10.1からdownload属性が利用できるにようになりました。
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#Browser_compatibility


CSVの生成

const arr = [
  ['ご利用年月日', 'ご利用"箇所', 'ご,利,用,額'],
  ['2017/01/29', '', '""345'],
  ['2017/02/01', '"AM"AZON.CO.JP', '7,362'],
];

/**
 * 各フィールドの囲い -> ダブルクォーテーション
 * 各フィールドの区切り -> カンマ
 * 改行コード -> LF
 */
function arrToCSV(arr) {
  return arr
  .map(row => row.map(str => '"' + (str ? str.replace(/"/g, '""') : '') + '"')
  )
  .map(row => row.join(','))
  .join('\n');
}

arrToCSV(arr);
// -> ""ご利用年月日","ご利用""箇所","ご,利,用,額"
// "2017/01/29","","""""345"
// "2017/02/01","""AM""AZON.CO.JP","7,362""

参考

ダウンロード

以下どれかを利用

msSaveBlob

  • IE (10以上) で動く
const data = arrToCSV(arr);

function download(data, name) {
  if (window.navigator.msSaveBlob) {
    // utf8
    const bom = '\uFEFF';
    const blob = new Blob([bom, data], { type: 'text/csv' });
    window.navigator.msSaveBlob(blob, name);
  }
}

download(data, 'filename.csv');

download属性

const data = arrToCSV(arr);

function download(data, name) {
  const anchor: any = document.createElement('a');
  if (window.URL && anchor.download !== undefined) {
    // utf8
    const bom = '\uFEFF';
    const blob = new Blob([bom, data], { type: 'text/csv' });
    anchor.download = name;

    // window.URL.createObjectURLを利用
    // https://developer.mozilla.org/ja/docs/Web/API/URL/createObjectURL
    anchor.href = window.URL.createObjectURL(blob);

    // これでも可
    // anchor.href = 'data:text/csv;charset=utf-8,' + encodeURIComponent(bom + data);

    // firefoxでは一度addしないと動かない
    document.body.appendChild(anchor);
    anchor.click();
    anchor.parentNode.removeChild(anchor);
  }
}

download(data, 'filename.csv');

Data URI scheme + data:attachment/…

  • 主にSafari対応
  • ファイル名を設定できない
  • 動作確認あんまりできていない
const data = arrToCSV(arr);

function download(data) {
  // utf8
  const bom = '\uFEFF';
  window.location.href =
    'data:attachment/csv;charset=utf-8,' + encodeURIComponent(bom + data);
}

download(data);

以下の方法でもできる(メモ)

// string to base64
function download_base64(data) {
  const bom = '\uFEFF';
  window.location.href =
    'data:attachment/csv;charset=utf-8;base64,' + btoa(unescape(encodeURIComponent(bom + data)));
}

// blob to dataurl
function download_filereader(data) {
  const bom = '\uFEFF';
  const reader = new window.FileReader();
  const blob = new Blob([bom, data], { type: 'attachment/csv' });
  reader.readAsDataURL(blob);
  reader.onloadend = () => {
    window.location.href = reader.result;
  }
}

サンプル

その他

  • 手元ではWin, Mac両方のエクセルで文字化けせず開けた
  • 調べてみると「UTF-16にする」「タブ区切りにする」「Shift JISにしないと結局だめ」とかあるっぽい
  • 様子見

参考