node.jsでexceljsを使ってUTF-8でCSVファイル出力する

課題

node.jsでExcelまたはCSVファイルを編集してファイルに出力したい

Excel操作パッケージ

xlsxも有名なようですが、exceljsが使いやすくマニュアルも分かりやすかったので、私はexceljsを採用しました。

exceljs
Excel Workbook Manager - Read and Write xlsx and csv Files.. Latest version: 4.3.0, last published: 2 years ago. Start using exceljs in your project by running ...

エンコード問題

本題です。

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 a Buffer into a string that does not exclusively contain valid UTF-8 data, the Unicode replacement character U+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 from U+0000 to U+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.
Buffer | Node.js v20.3.1 Documentation

また、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に変換する方法は以下のサイトが参考になります。
ただ、前述の通り非対応文字の処理に困るので私は不採用としました。

[React / JavaScript] ExcelJSで実装したCSV出力機能でSJIS変換対応をしてみた | DevelopersIO
こんにちは、CX事業本部 IoT事業部の若槻です。 前回のエントリでは、ExcelJSを使用してアプリにExcel/CSVのダウンロード機能を実装しましたが、その際のCSVの文字コードはUTF8でした。 [React / …

より良い方法があればコメント書いていってもらえると助かります。

以上

コメント

タイトルとURLをコピーしました