【问题标题】:Blob charset for CSV fileCSV 文件的 Blob 字符集
【发布时间】:2019-05-11 16:34:35
【问题描述】:

我想使用 blob 创建一个 CSV 文件。 该文件应该以 ANSI 编码,但它不起作用。

var blob = new Blob(["\ufeff", csvFile], { type: 'text/csv;charset=windows-1252;' });

文件始终使用 UTF-8 编码创建。

【问题讨论】:

  • 这个问题你回答了吗?
  • @DT 你能解释一下我目前的答案在你的情况下有什么问题吗?
  • 你的答案can't create a file encoding is ANSI.
  • 我必须下载一个包含任何文本的文件,如果在记事本中打开,它必须显示编码 ANSI。
  • @DT 你是什么意思?当然,它确实会创建一个以 ANSI 编码的文件。你的文件内容是什么?如果您的文件仅包含 ASCII 字符,则无论它被读取为 ASCII、ANSI 还是 UTF-8,所有 ASCII 字符都以这三种编码的相同方式表示。记事本所说的是它认为文件是如何编码的,而不一定是它是如何编码的。

标签: javascript character-encoding blob


【解决方案1】:

USVString(或JavaScript 字符串)传递给Blob's constructor 将在Blob 的数据中automatically encode it to UTF-8

type 选项仅供资源获取器使用,它用于模仿 HTTP 请求的 Content-Type 标头。
因此,例如,如果您通过 blob:// URI 获取或提供该 Blob,则将使用此 type 的值,类似地,如果您在没有 encoding 第二个参数的情况下调用 FileReader 的 readAsText( blob ) 方法,可能会用到charset= 的信息。

但是这个 type 选项根本不会改变 Blob 数据的所有内容

(async ()=> {

  const data = "é";
  const no_type = new Blob( [ data ] );
  const csv_windows1252 = new Blob( [ data ], { type: "text/csv;charset=Windows-1252" } );
  const image_png = new Blob( [ data ], { type: "image/png" } );

  // read as ArrayBuffer to see the exact binary content
  console.log( "no_type:", await hexDump( no_type ) ); // C3A9
  console.log( "csv_windows1252:", await hexDump( csv_windows1252 ) ); // C3A9
  console.log( "image_png:", await hexDump( image_png ) ); // C3A9

})();

async function hexDump( blob ) {
  const buf = await blob.arrayBuffer();
  const view = new Uint8Array( buf );
  const arr = [ ... view ];
  return arr.map( (val) => val.toString( 16 ) )
    .join( "" ).toUpperCase();
}

正如您在这个 sn-p 中看到的,无论 type 参数如何,所有这些 Blob 都包含完全相同的字节数据:C3 A9,对应于 UTF-8 表示é (U+00e9) 字符“UTF-8 (hex) 0xC3 0xA9 (c3a9)”。
ANSI (Windows-1252) 中,此字符由字节0xe9 (e9) 表示,因此如果我们的 Blob 确实保存了以 ANSI 编码的文本,它应该包含此字节。

查看它的一种方法是使用 TextDecoder 并尝试使用两种编码解码两个 Blob:

const UTF8Content = new Uint8Array( [ 0xC3, 0xA9 ] );
const ANSIContent = new Uint8Array( [ 0xE9 ] );

const UTF8Decoder = new TextDecoder( "utf-8" );
const ANSIDecoder = new TextDecoder( "windows-1252" );

console.log( "UTF8-content decoded as UTF8",
  UTF8Decoder.decode( UTF8Content )
); // é
console.log( "UTF8-content decoded as ANSI",
  ANSIDecoder.decode( UTF8Content )
); // é
console.log( "ANSI-content decoded as UTF8",
  UTF8Decoder.decode( ANSIContent )
); // �
console.log( "ANSI-content decoded as ANSI",
  ANSIDecoder.decode( ANSIContent )
); // é

因此,如您所愿,您需要从 TypedArray 生成 Blob,其中包含已以 ANSI 编码的数据。
曾经有一个选项使用 TextEncoder API 将 USVStrings 编码为任意编码,但这已从规范和浏览器中删除。

所以最简单的方法是使用库来执行转换。在这里,我将使用this one

const text = "é";
const data = new TextEncoder( "windows-1252", {
  NONSTANDARD_allowLegacyEncoding: true
} ).encode( text ); // now `data` is an Uint8Array

const blob = new Blob( [ "foo bar" ], { type: "text/csv" } ); // here you have your ANSI Blob

// Just to be sure
hexDump( blob ).then( console.log ); // E9

async function hexDump( blob ) {
  const buf = await blob.arrayBuffer();
  const view = new Uint8Array( buf );
  const arr = [ ...view ];
  return arr.map( (val) => val.toString( 16 ) )
    .join( "" ).toUpperCase();
}
<script>
  // we need to force installation of the library
  // by removing the built-in API
  window.TextEncoder = null;
</script>
<script src="https://cdn.jsdelivr.net/gh/inexorabletash/text-encoding/lib/encoding-indexes.js"></script>
<script src="https://cdn.jsdelivr.net/gh/inexorabletash/text-encoding/lib/encoding.js"></script>

As a fiddle with the download link 因为 stack-sn-ps 不允许再这样做了。


重要提示:

ANSI 仅支持有限的字符集,一些可以保存在 USVString 中的字符无法映射到 ANSI,因此您必须确保您的输入仅包含可映射的字符,否则会抛出强>:

const text = "?"; // can't be mapped to ANSI
const data = new TextEncoder( "windows-1252", {
  NONSTANDARD_allowLegacyEncoding: true
} ).encode( text ); // throws
<script>
  window.TextEncoder = null;
</script>
<script src="https://cdn.jsdelivr.net/gh/inexorabletash/text-encoding/lib/encoding-indexes.js"></script>
<script src="https://cdn.jsdelivr.net/gh/inexorabletash/text-encoding/lib/encoding.js"></script>

Ps:您在代码中添加到 Blob 数据的 \uFFFE 字符是 UTF-16 BOM。它仅帮助读者了解 UTF-16 编码文本的数据的预期字节顺序,它不会以任何方式对以下数据进行编码,并且在非 UTF-16 文件中根本没有帮助。

【讨论】:

  • 这个答案太详细了..太棒了!
猜你喜欢
  • 2013-12-11
  • 2011-08-09
  • 2019-05-15
  • 1970-01-01
  • 1970-01-01
  • 2020-02-19
  • 2019-12-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多