为什么 Blob of Array 比 Blob of Uint8Array 小?

Why is Blob of Array smaller than Blob of Uint8Array?

我使用 FileReader.readAsArrayBuffer 读取文件,然后执行如下操作:

  var compressedData = pako.gzip(new Uint8Array(this.result));
  var blob1 = new Blob([compressedData]); // size = 1455338 bytes
  var blob2 = new Blob(compressedData);   // size = 3761329 bytes

举个例子:如果结果有4194304字节,压缩后大小为1455338字节。但出于某种原因,Uint8Array 需要包装在一个数组中。这是为什么?

比照。 BLOB 构造函数的文档:

https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob

[the first argument] is an Array of ArrayBuffer, ArrayBufferView, Blob, DOMString objects, or a mix of any of such objects, that will be put inside the Blob. DOMStrings are encoded as UTF-8.

我不确定它在幕后是如何工作的,但基本上构造函数期望将一组内容打包到 BLOB 中。因此,在第一种情况下,您构建的是单个部分(即您的 ArrayBuffer)的 BLOB,而在第二种情况下,您是从 1455338 个部分(即每个字节单独)构建它。

由于文档说 BLOB 部分只能是数组或字符串,它可能最终将 ArrayBuffer 中的每个字节值转换为 UTF-8 字符串,这意味着它不是每个数字使用 1 个字节,而是使用每个十进制数字 1 个字节(两个结果大小的比率似乎支持这一点,因为单个字节值的长度为 1-3 位数字,较大的 BLOB 大约是较小的 BLOB 大小的 2.5 倍)。这不仅浪费,我敢肯定它还会使您的 ZIP 无法使用。

所以,底线是,第一个版本是正确的方法。

不幸的是,MDN 文章在这里几乎是错误的,充其量只是误导。

From the specs:

The Blob() constructor can be invoked with the parameters below:

  • A blobParts sequence which takes any number of the following types of elements, and in any order:

    • BufferSource elements.

    • Blob elements.

    • USVString elements.

  • ... [BlobPropertyBag, none of our business here]

所以这里的 序列 可以是很多东西,从 ArraySet 通过 multi-dimensional 数组。

那么算法就是遍历这个序列,直到找到上面三种元素中的一种。

那么在您的情况下发生的情况是 TypedArray 可以转换为序列 。这意味着当你将它作为直接参数传递时,它将看不到它的 ArrayBuffer 并且算法将遍历它的内容并获取值(这里是 8 位数字转换为字符串),这可能不是您所期望的。

另一方面,当您通过数组包装 Uint8Array 时,算法能够找到您的 Uint8Array 指向的 BufferSource。所以它将使用它代替(二进制数据,可能是你想要的)。

var arr = new Uint8Array(25);
arr.fill(255);
var nowrap = new Blob(arr);
var wrapped = new Blob([arr]);
test(nowrap, 'no wrap');
test(wrapped, 'wrapped');

function test(blob, msg) {
  var reader = new FileReader();
  reader.onload = e => console.log(msg, reader.result);
  reader.readAsText(blob);
}