往返 Blob 到 Array 将 48 添加到数组值

Round-tripping Blob to Array adds 48 to array values

我有两个函数可以在 Blob 和字节数组之间进行转换:

function arrayToBlob(data) {
    return new Blob(data);
}

function blobToArray(data, callback) {
    let reader = new FileReader();
    reader.addEventListener("loadend", function() {
        callback(Array.from(new Uint8Array(reader.result)));
    });
    reader.readAsArrayBuffer(data);
}

blobToArray 接受回调,因为它需要设置一个事件侦听器。)

我希望这些函数互为反函数,但是当我 运行

blobToArray(arrayToBlob([1,2,3]), console.log)

我得到的结果不是[1, 2, 3],而是[49, 50, 51]。大概我正在做的事情是将数字转换为它们的 ASCII 值,但我不知道是哪一部分负责。

A Blob 的行为就像一个文件,我在文档中的任何地方都没有看到将构造函数与数组一起使用,元素被视为文本(单独的字符),但它似乎确实如此,所以转换是在 Blob 构造中进行的(请注意,您没有为 Blob 提供任何 MIME 类型,但在我的测试中这不会影响这些函数的结果)。您可以使用我的示例中的第二个函数来验证它确实如此,将其作为文本结果读取为字符串 "123".

为了能够看到这一点,我经历了一些 quite extended and interesting article, and the conversion between ArrayBuffer to Uint8Array was originally suggested by this SO answer

另外,似乎为了更容易地存储和检索值,可以使用 DataView,没试过,但你可以找到 MDN reference here

function arrayToBlob(data) {
    return new Blob(data);
}

function blobToArray(data, callback) {
    let reader = new FileReader();
    reader.addEventListener("loadend", function() {
        callback( Array.from((new Uint8Array(reader.result)).map(function(a){ return String.fromCharCode(a); })) );
    });
    reader.readAsArrayBuffer(data);
}

function blobToArrayAsText(data, callback) {
    let reader = new FileReader();
    reader.addEventListener("loadend", function() {
        callback( Array.from(reader.result) ); //result is "123" here
    });
    reader.readAsText(data);
}

blobToArray(arrayToBlob([1,2,3]), console.log)

blobToArrayAsText(arrayToBlob([1,2,3]), console.log)

试试这个方法

function ArrToBlob(arr) {
    return new Blob([new Uint8Array(arr)]);
}

async function BlobToArr(blob) {
  return [...new Uint8Array(await new Response(blob).arrayBuffer())];
}


async function start() {
  let a=[1,2,3];
  let b= ArrToBlob(a);
  let c = await BlobToArr(b);
  
  let j=JSON.stringify;
  console.log('input :',j(a));  
  console.log('blob  :',j(b));  
  console.log('output:',j(c));
}


start();

您可以使用例如 Uint8Array 而不是 Uint8Array Int32Array 在数组中使用大于 255 的负数。我还使用 async/await 方法使代码看起来更同步且嵌套更少(如您所见,没有使用显式回调)。

问题是 Blob 的构造函数将数组中的数字转换为字符串。根据 MDN documentation Blob's constructor takes and array of an Array or ArrayBuffer, ArrayBufferView, Blob, DOMString objects, or a mix of any of such objects, as a first parameter. All these will be concatenated and put into the Blob. So each element in the array that you passed is treated on it's own. They are converted to strings (see ASCII table,'1' 的代码是 49 等等)并放入 Blob。
请注意,这 4 个表达式的结果是相同的:

function arrayToBlob(data) {
    return new Blob(data);
}

function blobToArray(data, callback) {
    let reader = new FileReader();
    reader.addEventListener("loadend", function() {
        callback(Array.from(new Uint8Array(reader.result)));
    });
    reader.readAsArrayBuffer(data);
}

blobToArray(arrayToBlob([1,2,3]), console.log)
blobToArray(arrayToBlob(['1','2','3']), console.log)
blobToArray(arrayToBlob([123]), console.log)
blobToArray(arrayToBlob(['123']), console.log)

如果你想得到一个二进制数组,你需要传递一个适当的二进制数组给 Blob:

function arrayToBlob(data) {
    return new Blob([data]);
}

function blobToArray(data, callback) {
    let reader = new FileReader();
    reader.addEventListener("loadend", function() {
        callback(Array.from(new Uint8Array(reader.result)));
    });
    reader.readAsArrayBuffer(data);
}

var arr = new Uint8Array(3);
arr[0]=1;
arr[1]=2;
arr[2]=3;

blobToArray(arrayToBlob(arr), console.log)

请注意我是如何将 Uint8Array 传递给 Blob 的:return new Blob([data]);。我将它放在一个数组中,因此它不会被视为 Blob 作为第一个参数的对象数组本身。
总之:您并没有真正进行往返,您从一种类型的数组开始并将其转换为另一种类型的数组。如果您从一开始就使用正确的数组,那么一切都有效。