Круговое отключение Blob to Array добавляет 48 к значениям массива - PullRequest
0 голосов
/ 13 февраля 2019

У меня есть две функции для преобразования между Blob s и массивами байтов:

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, но я не знаю, какая часть ответственна.

Ответы [ 3 ]

0 голосов
/ 13 февраля 2019

Попробуйте вот так

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 вы можете использовать, например, Int32Array для использования отрицательных и больших чисел, чем 255 в вашем массиве.Я также использую подход async / await, чтобы код выглядел более синхронным и менее вложенным (как вы можете видеть, обратный вызов не используется).

0 голосов
/ 13 февраля 2019

Проблема в том, что конструктор Blob преобразует числа в вашем массиве в строки.Согласно документации MDN конструктор Blob принимает и массив объектов Array или ArrayBuffer, ArrayBufferView, Blob, DOMString илисмесь любого из таких объектов, в качестве первого параметра.Все они будут объединены и помещены в Blob.Таким образом, каждый элемент в массиве, который вы передали, обрабатывается отдельно.Они преобразуются в строки (см. Таблицу ASCII , код «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 принимает в качестве 1-го параметра.
В заключение: вы на самом деле не выполняли круговую передачу, вы начали с одного типа массива и преобразовали егов другой тип массива.Если вы используете массив propper с самого начала, то все работает.

0 голосов
/ 13 февраля 2019

A Blob ведет себя как файл, я не видел нигде в документации, что при использовании конструктора с массивом элементы передаются как текст (отдельные символы), но, похоже, так и происходит, поэтому преобразование выполняется вконструкция Blob (обратите внимание, что вы не предоставляете тип MIME для BLOB-объекта, но в моих тестах это не повлияло на результат этих функций).Вы можете проверить с помощью второй функции в моем примере, что она делает, читая ее как текст, в результате получается строка "123".

Чтобы увидеть это, я прошел через несколько довольно расширенных и интересныхстатья , и преобразование между ArrayBuffer в Uint8Array было первоначально предложено этим ответом SO .

Также кажется, что для более простого хранения и получения значений можноиспользуйте DataView, не пробовал, но вы можете найти MDN ссылку здесь

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)
...