下载类型为“text/csv”的Blob会删除Unicode BOM

iyfamqjs  于 2023-07-31  发布在  其他
关注(0)|答案(3)|浏览(97)

我试图保存一个CSV文件使用JavaScript,与前置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 = '\ufeff\ufefftest,test2';


生成的文件应在开头具有BOM表字符。
为什么在本例中要剥离它?
编辑:我的用例是生成一个CSV文件,并确保该文件可以通过Microsoft Excel以正确的编码打开。我在想,也许BOM被检测到并被截断,但Excel需要该字符存在才能检测到UTF-8。

e5nqia27

e5nqia271#

我最好的猜测是,一些浏览器可能会解释文本中的BOM并截断它。
我添加了一个示例,其中BOM由ArrayBuffer添加到Blob中。这似乎起作用了。
但是请注意,您尝试添加的BOM是UTF-16 (BE) BOM,而不是UTF-8一个EF BB BFhttps://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();

字符串

h6my8fg2

h6my8fg22#

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

字符串

hc8w905p

hc8w905p3#

你的BOM在这里。
这很简单,无论你用什么来阅读它,它都被丢弃了,因为,嗯,它不应该是文本的一部分。
然而,如果你创建一个HEX转储或将其作为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);
}

个字符
请注意,另一个答案是正确的,因为您的BOM实际上是UTF-16 BE的BOM,但这还不是您的问题。

相关问题