みんなのちからになりたい

コピペでブログラムつくっていきたい

Express4でShift_JISのCSVをダウンロードさせる

DB に入ってるデータを CSV に出力する場合、文字コードがUTF8でよければあっさりいけるんだけども、Shift_JIS で吐いてくださいとか言われると難易度があがってけっこうめんどくさかったのでメモ。

UTF8でも問題ない場合

なにも考えず node-csv で普通に吐いて res.download しましょう。 csv.adaltas.com

ちなみに node-csv 初めて使ったけど、0.4系とそれ以外では書き方が違うしめんどいのでぼくは0.3系を使った(個人の感想です)

Shift_JISで吐くけどダウンロードはさせなくてもよい場合

以下がすごく参考になるのでありがたく写経しましょう。 qiita.com

要は、CSV に吐き出すときに pipe で Iconv 挟んで出力するという感じのようです。

Shift_JISで吐いてさらにダウンロードさせる場合

上のやり方で最後に res.download させればいいと思っていたらうまくいかなかったって話。

理由としては、stream が投げる Event の close ではまだ Iconv の変換が終わっておらずファイルが close されていないため、そこで res.download させても変換前のファイルもしくは単に空のファイルが返るだけということ (もしかしたらぼくのやり方が悪いだけでちゃんとしたらうまくいくのかもしれない)

なので、pipe で渡さず普通に to に渡せば close ではちゃんとファイルが閉じられているので、そこで Iconv で変換してファイルに書き戻すというやり方をしたらうまくいった。

// CSV出力
csv().from(result).to(filename, { quoted: true })
.on('close', function(){
  console.log('close');
  // utf8からShift_JISに変換
  var contents = fs.readFileSync(filename, { encoding: 'utf8' });
  var iconv = new Iconv('UTF-8', 'Shift_JIS//TRANSLIT//IGNORE');
  var sjiscontents = iconv.convert(contents);
  fs.writeFileSync(filename, sjiscontents, { encoding: null });
  res.download(filename);
})
.on('error', function(error){
  console.log(error.message);
});

結論

Shift_JISで吐くな