課題
node.jsでExcelまたはCSVファイルを編集してファイルに出力したい
Excel操作パッケージ
xlsxも有名なようですが、exceljsが使いやすくマニュアルも分かりやすかったので、私はexceljsを採用しました。
エンコード問題
本題です。
exceljsのcsv出力を使用すると、Excelで開いた際に日本語が文字化けする問題があります。
ExcelはデフォルトではShift-JISで処理するようで(日本版だけ?)、この問題に対処するためには、Shift-JISに変換するか、BOMと呼ばれるヘッダを設定してUTF-8であることを明示する必要があります。
exceljsにはencordingのオプションもあるのですが、「utf8」「utf16le」「latin1」しか対応しておらず、その他のエンコードには出力できません。
The character encodings currently supported by Node.js are the following:
'utf8'
(alias:'utf-8'
): Multi-byte encoded Unicode characters. Many web pages and other document formats use UTF-8. This is the default character encoding. When decoding aBuffer
into a string that does not exclusively contain valid UTF-8 data, the Unicode replacement characterU+FFFD
� will be used to represent those errors.'utf16le'
(alias:'utf-16le'
): Multi-byte encoded Unicode characters. Unlike'utf8'
, each character in the string will be encoded using either 2 or 4 bytes. Node.js only supports the little-endian variant of UTF-16.'latin1'
: Latin-1 stands for ISO-8859-1. This character encoding only supports the Unicode characters fromU+0000
toU+00FF
. Each character is encoded using a single byte. Characters that do not fit into that range are truncated and will be mapped to characters in that range.
また、Shift-JIS に変換したとしても、Shift-JIS には UTF-8 でしか表現できない文字があると欠落する問題があります。
対策
対策として、UTF-8にファイル出力した後に、BOMヘッダーを追加することにしました。
※ できれば出力時に追加したいのですがやり方わからず。。。
コードは以下のようになります。
workbook.csv.writeFile でutf8にファイル出力し、
出力したファイルを全て読み込み、BOMを追加して書き込むだけです。
await workbook.csv.writeFile(outputPath, {
encoding: "utf8"
});
//BOMを追加。無いとExcelで文字化けする
const text = fs.readFileSync(outputPath, { encoding: 'utf-8' });
const bom = '\ufeff'
fs.writeFileSync(outputPath, bom + text);
シンプルですが、このコードはメモリーにデータを展開するためファイルサイズが小さいケースに限ります。
ファイルサイズが大きい場合はバッファリングした方が良いと思います。
なお、Shift-JISに変換する方法は以下のサイトが参考になります。
ただ、前述の通り非対応文字の処理に困るので私は不採用としました。
より良い方法があればコメント書いていってもらえると助かります。
以上
コメント