为什么 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 文章在这里几乎是错误的,充其量只是误导。
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]
所以这里的 序列 可以是很多东西,从 Array
到 Set
通过 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);
}
我使用 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 文章在这里几乎是错误的,充其量只是误导。
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]
所以这里的 序列 可以是很多东西,从 Array
到 Set
通过 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);
}