2

我使用读取文件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 包装在一个数组中。为什么是这样?

4

2 回答 2

3

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

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

[第一个参数] 是 ArrayBuffer、ArrayBufferView、Blob、DOMString 对象或任何此类对象的组合,它们将被放入 Blob 中。DOMStrings 被编码为 UTF-8。

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

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

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

于 2018-03-29T09:35:05.603 回答
1

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

从规格

可以使用以下参数调用 Blob() 构造函数:

  • 一个 blobParts 序列,它采用任意数量的以下类型的元素,并且以任意顺序:

    • 缓冲源元素。

    • 斑点元素。

    • USVString 元素。

  • ... [BlobPropertyBag,这里不关我们的事]

所以这里的序列可以是很多东西,从一个Array到一个Set通过多维数组。

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

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

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

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

于 2018-03-29T11:12:53.617 回答