我正在尝试使用JavaScript和前置的UTF-8 BOM保存CSV文件。但是,在检查下载的文件时,似乎总是会删除BOM。以下代码重现了该问题:
var csv = '\ufefftest,test2';
var blob = new Blob([csv], {type: 'text/csv;charset=utf-8'});
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = 'test.csv';
document.body.appendChild(a);
a.click();
将BOM表字符两次添加到字符串会产生正确的结果:
var csv = '\ufeff\ufefftest,test2';
结果文件的开头应具有BOM字符。
为什么在此示例中将其剥离?
编辑:我的用例是生成CSV文件,并确保可以使用Microsoft Excel以正确的编码打开文件。我认为可能是BOM已被检测到并被截断,但是Excel需要显示该字符才能检测UTF-8。
答案 0 :(得分:2)
我最好的猜测是某些浏览器可能会解释文本中的BOM并将其截断。
我添加了一个示例,其中BOM由ArrayBuffer
添加到Blob
。这似乎在起作用。
但是请注意,您要添加的BOM是UTF-16 (BE)
BOM,而不是UTF-8一个EF BB BF
。
https://de.wikipedia.org/wiki/Byte_Order_Mark
var csv = 'test,test2';
// create BOM UTF-8
var buffer = new ArrayBuffer(3);
var dataView = new DataView(buffer);
dataView.setUint8(0, 0xfe);
dataView.setUint8(1, 0xbb);
dataView.setUint8(2, 0xbf);
var read = new Uint8Array(buffer);
// create BOM UTF-16
var buffer = new ArrayBuffer(2);
var dataView = new DataView(buffer);
dataView.setUint8(0, 0xfe);
dataView.setUint8(1, 0xff);
var read = new Uint8Array(buffer);
var blob = new Blob([read /*prepend bom*/, csv], {type: 'text/csv;charset=utf-8'});
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = 'test.csv';
document.body.appendChild(a);
a.click();
答案 1 :(得分:0)
您的BOM表在这里。
仅仅是因为您用来阅读它的所有内容都将其丢弃,因为,它不应该是文本的一部分。
但是,如果您进行十六进制转储或将其读取为ArrayBuffer,则会看到它仍然存在:
const csv = '\ufefftest,test2';
const blob = new Blob([csv], {type: 'text/csv;charset=utf-8'});
download(blob);
read(blob);
inp.onchange = e => read(inp.files[0]);
async function read(blob) {
// grab the byte content
const buf = await new Response(blob).arrayBuffer();
// stupidly map to some string characters
const str = [...new Uint8Array(buf)]
.map(c => String.fromCharCode(c)); // only for the demo, this doesnt convert from bytes to string in UTF-8!
console.log(str);
}
function download(blob) {
const a = document.createElement('a');
a.download = 'file.csv';
a.href = URL.createObjectURL(blob);
a.textContent = 'download';
document.body.prepend(a);
}
<br><label>you can reupload it here too<input type="file" id="inp"></label>
请注意,另一个答案是正确的,因为您的BOM实际上是UTF-16BE的BOM,但这不是您的问题。
答案 2 :(得分:0)
var csv = 'test,test2';
var blob = new Blob([decodeURIComponent('%ef%bb%bf') /*prepend bom*/, csv], {type: 'text/csv;charset=utf-8'});
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = 'test.csv';
document.body.appendChild(a);
a.click();