下载类型为"text/csv"条带的 Blob Unicode BOM



我正在尝试使用javaScript保存CSV文件,并使用预审车的UTF-8 BOM保存。但是,在检查下载的文件时,似乎总是剥去了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 = 'ufeffufefftest,test2';

生成的文件应在开始时具有BOM字符。

为什么在此示例中被剥离?

编辑:我的用例正在生成CSV文件,并确保可以通过Microsoft Excel正确编码来打开该文件。我认为也许检测和截断了BOM,但是Excel需要角色才能检测到UTF-8。

我最好的猜测是,有些浏览器可能会解释文本中的bom并截断。

我添加了一个示例,其中 ArrayBuffer添加了bom到 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();

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();

您的bom在这里。

简单地说,无论您用来阅读它都会放弃它,因为它不应该是文本的一部分。
但是,如果您进行十六进制或将其读成阵列式扣子,您会发现它仍然存在:

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之一,但这还不是您的问题。

最新更新