微信小程序/Excel UTF-8编码问题及其相关
打算用微信小程序将数据存为UTF-8格式的CSV,让Excel编辑.
使用wx.writeFile
或者writeFileSync
可以设置编码为UTF-8保存. 但此后的坑就连续不断出现了.
通过shareFileMessage
转给自己, 用Excel打开, 就会发现是乱码. 原因是Excel只支持带BOM的UTF-8. 开始解决这个问题, 然而微信和Excel都有坑, 分别说下:
微信的系统差异
要给文件前面加UTF-8 BOM, 最简单是在保存的字符串前加入 \ufeff
再用writeFile
+UTF8格式保存. 你会发现Android版本微信很好地完成了这个任务, Excel顺利打开, 然而ios版本微信会把你加入的\ufeff
自动删除! 保存了个寂寞
微信用binary方式保存
问遍教程,都会让你用Buffer和TextEncoder通过UTF8编码转为ArrayBuffer前面再加入BOM头0xEF、0xBB、0xBF
, 但是微信小程序不支持这两个常见的类Buffer和TextEncoder. 除非你自己实现一个.
微信曲线救国方式
碰到ios, 先保存,再读取,再在前面加入BOM头,再保存. 利用微信writeFile保存功能支持UTF8来解决
tableStr = '\ufeff' + tableStr // 增加UTF8 BOM头
const fs = wx.getFileSystemManager()
fs.writeFileSync(filename, tableStr, 'utf-8')
const deviceInfo = wx.getDeviceInfo()
if(deviceInfo.platform == 'ios'){
// 由于iOS系统上会把utf8保存的文件的前面的bom头删除(android不会),所以需要以arrayBuffer的方式读入文件之后重新加上utf8 BOM头。
// 之所以不在内存中完成转换,而是通过文件读写的方式转换, 原因是内存中转换字符串到Utf8的两种手段Buffer/TextEncoder在微信小程序中都不支持。
let file = fs.readFileSync(filename)
const bom = new Uint8Array([0xEF, 0xBB, 0xBF]);
// 将文件内容转换为 Uint8Array 并合并
const contentArray = new Uint8Array(file);
const mergedArray = new Uint8Array(bom.length + contentArray.length);
mergedArray.set(bom, 0);
mergedArray.set(contentArray, bom.length);
fs.writeFileSync(filename, mergedArray.buffer, 'binary')
}
Excel的坑: 从2016版本才开始支持CSV UTF-8格式
如果你是2016以前的版本就不要挣扎了, 还不如用Win10/11上的记事本编辑了.