JavaScriptでCSVやテキストファイルなどを出力したとき、文字化けを起こしてしまうことがある。

CSV形式で出力して、テキストエディタでは読めるけど、Excelで開くと文字化けするなど。

結論からいうと、テキストの先頭にBOMをつければよい。
各ブラウザ(Chrome, Egde, Firefox, IE11, Safari, Opera)でファイルを出力するときに文字化けしない実装をまとめる。

BOM(Byte Order Mark)とは

Unicodeの符号化形式で符号化したテキストの先頭につける数バイトのデータのことである。
このデータを元にUnicodeで符号化されていることおよび符号化の種類の判別に使用する。
バイトオーダーマーク - Wikipedia

BOM付きファイルを出力する




var csv = 'ここにCSVのデータを入れる';

var link = document.createElement('a');
var bom = new Uint8Array([0xEF, 0xBB, 0xBF]);
var blob;

if (window.navigator.msSaveOrOpenBlob) {
  // Internet Explorer 11
  blob = new Blob([bom, csv], {type: 'text/csv'});
  window.navigator.msSaveOrOpenBlob(blob, csvName);
} else if (window.webkitURL && window.webkitURL.createObjectURL) {
  // Google Chrome and Safari
  blob = new Blob([bom, csv], {type: 'text/csv'});
  link.setAttribute('download', csvName);
  link.setAttribute('href', window.webkitURL.createObjectURL(blob));
  link.click();
} else if (window.URL && window.URL.createObjectURL) {
  // Firefox
  blob = new Blob([bom, csv], {type: 'text/csv'});
  link.setAttribute('download', csvName);
  link.setAttribute('href', window.URL.createObjectURL(blob));
  link.click();
}


new Uint8Array([0xEF, 0xBB, 0xBF]) がUTF-8のBOMになる。
new Blob([bom, csv]) でBOM付きのファイルをつくる。

あとはブラウザによって出力方法を変えている。
ただし、Safariの場合はうまく動作しないので注意!
 

ファイルのアップロード・ダウンロードを実装する

JavaScriptでファイルをアップロード・ダウンロードする実装方法をまとめる。  

ファイルのアップロード・ダウンロードを実装する



<!doctype html>
<html lang="ja">

<head>
    <meta charset="utf-8">
    <title>ファイルのアップロードとダウンロード</title>
</head>
<body>
    <div>
        <button id="upload">upload</button>
        <span id="download"></span>
    </div>
    <div>
        <input type="file" id="upload-file" />
        <textarea id="upload-text" readonly></textarea>
    </div>
    <script src="index.js"></script>
</body>
</html>
 


var upload = document.getElementById('upload');

// uploadボタンを使わずファイル選択したらすぐuploadしたい場合は、changeを使う
// uploadFile.addEventListener('change', function() {

// uploadボタンをクリックでアップロード処理をし、ダウンロード用リンクを作成する
upload.addEventListener('click', function () {
    var uploadFile = document.getElementById('upload-file');
    var file = uploadFile.files[0];
    if (!file) alert('ファイルを選択してください。');

    /********************************
      * upload処理
      ********************************/
    var uploadData;
    var uploadText = document.getElementById('upload-text');
    var reader = new FileReader();

    reader.readAsText(file);
    reader.onload = function () {
        // そのまま表示
        uploadText.innerHTML = reader.result;
        // JSONに変換
        uploadData = JSON.parse(reader.result);
    }

    /********************************
      * download用リンクの作成
      ********************************/
    //reader.onloadが非同期処理なので、1秒遅延させる
    setTimeout(function () {
        var downloadFile = JSON.stringify(uploadData);
        var a = document.createElement('a');
        a.textContent = 'download';
        a.download = 'file.json';
        a.href = URL.createObjectURL(new Blob([downloadFile], {type: 'text.plain'}));
        a.dataset.downloadurl = ['text/plain', a.download, a.href].join(':');

        var downloadLink = document.getElementById('download');
        downloadLink.appendChild(a);
    }, 1000);
});

各ブラウザ(Chrome, Firefox, Edge, IE11, Safari)でダウンロード処理を実装する

Webページから何らかのファイルをダウンロードしたい場合は、ブラウザごとに実装する必要がある。 以下のブラウザを対象とする。

  • Chrome
  • Firefox
  • Edge
  • Internet Explorer 11
  • Safari

ダウンロード処理を実装する



// ダウンロードしたいコンテンツ、MIMEType、ファイル名
var content  = 'abc';
var mimeType = 'text/plain';
var name     = 'test.txt';

// BOMは文字化け対策
var bom  = new Uint8Array([0xEF, 0xBB, 0xBF]);
var blob = new Blob([bom, content], {type : mimeType});

var a = document.createElement('a');
a.download = name;
a.target   = '_blank';

if (window.navigator.msSaveBlob) {
  // for IE
  window.navigator.msSaveBlob(blob, name)
}
else if (window.URL && window.URL.createObjectURL) {
  // for Firefox
  a.href = window.URL.createObjectURL(blob);
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
}
else if (window.webkitURL && window.webkitURL.createObject) {
  // for Chrome
  a.href = window.webkitURL.createObjectURL(blob);
  a.click();
}
else {
  // for Safari
  window.open('data:' + mimeType + ';base64,' + window.Base64.encode(content), '_blank');
}

Edge, Internet Explorer 11

window.navigator.msSaveBlob を使う。

Firefox

<a>タグを作成し、そのリンクにwindow.URL.createObjectURLを設定すれば、a.clickでダウンロード処理を実行することができる。ただし、clickイベントを発火する前にbodyなどに追加しなければ正常に動作しないので注意。もちろんclickイベントが終わったらremoveChildで削除する。

Chrome

window.webkitURL.createObjectURLを使う。Firefoxの処理に似ているが違いとしては、Chromeの場合はbodyなどに追加しなくてもメモリ上だけで対応できるという点がある。だからappendChildもremoveChildもする必要がない。