节前最后一天,不让人省心的运营同学又出了个新需求:每天定时导出某某统计数据。
为了快速完成任务,决定用 Node.js 来写,csv 库用的则是 csv-writer 这个 npm 包。
大体要用的代码如下:
安装依赖
npm i csv-writer
从数据库取出数据,写入 csv 文件:
const createCsvWriter = require('csv-writer').createObjectCsvWriter;
const csvWriter = createCsvWriter({
path: 'path/to/file.csv',
header: [ // 表头
{ id: 'name', title: 'NAME' },
{ id: 'lang', title: 'LANGUAGE' },
],
});
// 数据库中取的数据
const records = [
{ name: 'Bob', lang: 'French, English' },
{ name: 'Mary', lang: 'English' },
];
// 写入文件
csvWriter.writeRecords(records).then(() => {
console.log('...Done');
});
考虑到大家用的系统不同,所以对 Numbers 和 Excel 都做了测试。
运行上述代码,查看生成的效果:
Mac 下 Numbers 软件的打开效果:

Mac 下 Excel 软件的打开效果:

乍一看好像没什么问题,但当数据中出现中文时,区别就出来了:
// 带有中文的数据
const records = [
{ name: 'Bob', lang: 'French, English' },
{ name: 'Mary', lang: 'English' },
{ name: '尤慕', lang: '汉语' },
];
Numbers 仍然能正常显示:

Excel 则残了:

为什么 Excel 会乱码?通过搜索网络,在知乎上看到如下解答:
对于 CSV 文件,Excel 需要它有一个元信息来说明它的编码,那 CSV 是纯文本文件怎么设置元信息呢?微软就定义了一个自己的格式叫 BOM 头,这个 BOM 头在被其他的表格展示器(比如 Numbers 或者 Libre Office)打开的时候会被忽略,但对 Excel 就很关键了。(源[1])
作者所说的 BOM 头,就是在 csv 文件的头部,加入一个 \uFEFF
字符。
我们打开刚才程序生成的 csv 文件,可以看到如下内容:
NAME,LANGUAGE
Bob,"French, English"
Mary,English
尤慕,汉语
所以我们要做的,是在第一行的开头,加入\uFEFF
。程序改动如下:
const csvWriter = createCsvWriter({
path: 'file.csv',
header: [
// 注意这里,NAME 前加了 BOM 头
{ id: 'name', title: '\uFEFFNAME' },
{ id: 'lang', title: 'LANGUAGE' },
],
});
再次运行程序生成 csv,发现 Excel 软件也能正常显示了:

Numbers 打开也不受影响:

很神奇是不是?
好奇的同学可以用 less
命令查看新生成的 csv 文件的内容,在终端下可以发现那个神奇的字符:

可以设想,如果拿到的一个 csv 文件打开时有乱码,而文件又不是自己生成的,可以尝试如下方式来修复:
# 假设乱码的 csv 叫 a.csv
# 我们可以以它为基础
# 创建一个带有 BOM 头的 b.csv
echo -n '\uFEFF' > b.csv
cat a.csv >> b.csv
# 如此一来,b.csv 就能正常显示了
谢谢阅读,提前祝你春节快乐!
参考资料
csv 文件打开乱码,有哪些方法可以解决?: https://www.zhihu.com/question/21869078/answer/350728339




