Поиск…
замечания
Типизированные массивы были первоначально указаны в проекте редактора Khronos , а затем стандартизованы в ECMAScript 6 §24 и §22.2 .
Blobs заданы рабочим проектом W3C File API .
Преобразование между Blobs и ArrayBuffers
JavaScript имеет два основных способа представления двоичных данных в браузере. ArrayBuffers / TypedArrays содержат изменчивые (хотя и фиксированные) двоичные данные, с которыми вы можете напрямую манипулировать. Blobs содержат неизменяемые двоичные данные, доступ к которым возможен только через асинхронный интерфейс File.
Преобразование Blob
в ArrayBuffer
(асинхронный)
var blob = new Blob(["\x01\x02\x03\x04"]),
fileReader = new FileReader(),
array;
fileReader.onload = function() {
array = this.result;
console.log("Array contains", array.byteLength, "bytes.");
};
fileReader.readAsArrayBuffer(blob);
Преобразование Blob
в ArrayBuffer
с использованием Promise
(асинхронный)
var blob = new Blob(["\x01\x02\x03\x04"]);
var arrayPromise = new Promise(function(resolve) {
var reader = new FileReader();
reader.onloadend = function() {
resolve(reader.result);
};
reader.readAsArrayBuffer(blob);
});
arrayPromise.then(function(array) {
console.log("Array contains", array.byteLength, "bytes.");
});
Преобразование ArrayBuffer
или типизированного массива в Blob
var array = new Uint8Array([0x04, 0x06, 0x07, 0x08]);
var blob = new Blob([array]);
Манипулирование массивами с помощью DataViews
DataViews предоставляют методы для чтения и записи отдельных значений из ArrayBuffer, а не для просмотра всего объекта как массива одного типа. Здесь мы устанавливаем два байта отдельно, а затем интерпретируем их вместе как 16-разрядное целое без знака, первое из которых является big-endian then little-endian.
var buffer = new ArrayBuffer(2);
var view = new DataView(buffer);
view.setUint8(0, 0xFF);
view.setUint8(1, 0x01);
console.log(view.getUint16(0, false)); // 65281
console.log(view.getUint16(0, true)); // 511
Создание TypedArray из строки Base64
var data =
'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACN' +
'byblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHx' +
'gljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';
var characters = atob(data);
var array = new Uint8Array(characters.length);
for (var i = 0; i < characters.length; i++) {
array[i] = characters.charCodeAt(i);
}
Использование TypedArrays
TypedArrays - это набор типов, предоставляющих различные виды в изменяемые бинарные массивы ArrayBuffers с фиксированной длиной. По большей части они действуют как массивы, которые принуждают все назначенные значения к заданному числовому типу. Вы можете передать экземпляр ArrayBuffer в конструктор TypedArray для создания нового представления его данных.
var buffer = new ArrayBuffer(8);
var byteView = new Uint8Array(buffer);
var floatView = new Float64Array(buffer);
console.log(byteView); // [0, 0, 0, 0, 0, 0, 0, 0]
console.log(floatView); // [0]
byteView[0] = 0x01;
byteView[1] = 0x02;
byteView[2] = 0x04;
byteView[3] = 0x08;
console.log(floatView); // [6.64421383e-316]
ArrayBuffers можно скопировать с использованием .slice(...)
, либо напрямую, либо через представление TypedArray.
var byteView2 = byteView.slice();
var floatView2 = new Float64Array(byteView2.buffer);
byteView2[6] = 0xFF;
console.log(floatView); // [6.64421383e-316]
console.log(floatView2); // [7.06327456e-304]
Получение двоичного представления файла изображения
Этот пример вдохновлен этим вопросом .
Предположим, вы знаете, как загрузить файл с помощью File API .
// preliminary code to handle getting local file and finally printing to console
// the results of our function ArrayBufferToBinary().
var file = // get handle to local file.
var reader = new FileReader();
reader.onload = function(event) {
var data = event.target.result;
console.log(ArrayBufferToBinary(data));
};
reader.readAsArrayBuffer(file); //gets an ArrayBuffer of the file
Теперь мы выполняем фактическое преобразование данных файла в 1 и 0 с помощью DataView
:
function ArrayBufferToBinary(buffer) {
// Convert an array buffer to a string bit-representation: 0 1 1 0 0 0...
var dataView = new DataView(buffer);
var response = "", offset = (8/8);
for(var i = 0; i < dataView.byteLength; i += offset) {
response += dataView.getInt8(i).toString(2);
}
return response;
}
DataView
позволяет читать / записывать числовые данные; getInt8
преобразует данные из позиции байта - здесь 0
, значение, переданное в - в ArrayBuffer
к подписанному 8-битовому целочисленному представлению, а toString(2)
преобразует 8-разрядное целое в формат двоичного представления (то есть строку из 1 и 0 ').
Файлы сохраняются как байты. Значение «магического» смещения получается, если мы принимаем файлы, хранящиеся в байтах, т. Е. Как 8-битные целые числа и считываем их в 8-битном целочисленном представлении. Если бы мы пытались прочитать наши байтовые (т. Е. 8-битные) файлы в 32-битные целые числа, отметим, что 32/8 = 4 - это количество байтовых пробелов, которое является нашим значением смещения байта.
Для этой задачи DataView
s излишне. Они обычно используются в случаях, когда встречаются сущность или неоднородность данных (например, при чтении PDF-файлов, которые имеют заголовки, закодированные в разных базах, и мы хотели бы осмысленно извлечь это значение). Поскольку нам просто нужно текстовое представление, мы не заботимся о гетерогенности, поскольку никогда не нужно
Решение гораздо лучше - и короче - можно найти с помощью массива, типизированного в UInt8Array
, который обрабатывает весь ArrayBuffer
как состоящий из 8-битных целых чисел без знака:
function ArrayBufferToBinary(buffer) {
var uint8 = new Uint8Array(buffer);
return uint8.reduce((binary, uint8) => binary + uint8.toString(2), "");
}
Итерация через массивBuffer
Для удобного способа итерации через arrayBuffer вы можете создать простой итератор, который реализует методы DataView
под капотом:
var ArrayBufferCursor = function() {
var ArrayBufferCursor = function(arrayBuffer) {
this.dataview = new DataView(arrayBuffer, 0);
this.size = arrayBuffer.byteLength;
this.index = 0;
}
ArrayBufferCursor.prototype.next = function(type) {
switch(type) {
case 'Uint8':
var result = this.dataview.getUint8(this.index);
this.index += 1;
return result;
case 'Int16':
var result = this.dataview.getInt16(this.index, true);
this.index += 2;
return result;
case 'Uint16':
var result = this.dataview.getUint16(this.index, true);
this.index += 2;
return result;
case 'Int32':
var result = this.dataview.getInt32(this.index, true);
this.index += 4;
return result;
case 'Uint32':
var result = this.dataview.getUint32(this.index, true);
this.index += 4;
return result;
case 'Float':
case 'Float32':
var result = this.dataview.getFloat32(this.index, true);
this.index += 4;
return result;
case 'Double':
case 'Float64':
var result = this.dataview.getFloat64(this.index, true);
this.index += 8;
return result;
default:
throw new Error("Unknown datatype");
}
};
ArrayBufferCursor.prototype.hasNext = function() {
return this.index < this.size;
}
return ArrayBufferCursor;
});
Затем вы можете создать итератор следующим образом:
var cursor = new ArrayBufferCursor(arrayBuffer);
Вы можете использовать hasNext
чтобы проверить, есть ли еще элементы
for(;cursor.hasNext();) {
// There's still items to process
}
Вы можете использовать next
метод для следующего значения:
var nextValue = cursor.next('Float');
С таким итератором писать собственный парсер для обработки двоичных данных становится довольно легко.