- JavaScript Двоичные данные
- Преобразование между Blobs и ArrayBuffers
- Преобразование Blob в ArrayBuffer (асинхронный)
- Преобразование Blob в ArrayBuffer с использованием Promise (асинхронный)
- Преобразование ArrayBuffer или типизированного массива в Blob
- Манипулирование массивами с помощью DataViews
- Создание TypedArray из строки Base64
- Использование TypedArrays
- Получение двоичного представления файла изображения
- Итерация через массивBuffer
- How to go from Blob to ArrayBuffer
JavaScript
Двоичные данные
Типизированные массивы были первоначально указаны в проекте редактора Khronos , а затем стандартизованы в ECMAScript 6 §24 и §22.2 .
Преобразование между 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
Использование 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]
Получение двоичного представления файла изображения
// 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 чтобы проверить, есть ли еще элементы
Вы можете использовать next метод для следующего значения:
var nextValue = cursor.next('Float');
С таким итератором писать собственный парсер для обработки двоичных данных становится довольно легко.
- Начало работы с JavaScript
- .postMessage () и MessageEvent
- AJAX
- API веб-криптографии
- API вибрации
- API выбора
- API состояния батареи
- API уведомлений
- Callbacks
- execCommand и contenteditable
- IndexedDB
- JSON
- Linters — Обеспечение качества кода
- Loops
- requestAnimationFrame
- Timestamps
- Transpiling
- WeakMap
- WeakSet
- WebSockets
- Автоматическая точка с запятой — ASI
- Анти-паттерны
- Арифметика (математика)
- Асинхронные итераторы
- Асинхронные функции (async / await)
- Атрибуты данных
- Веб-хранилище
- Встроенные константы
- Генераторы
- геолокации
- Глобальная обработка ошибок в браузерах
- Дата
- Двоичные данные
- Единичное тестирование Javascript
- Задавать
- Зарезервированные ключевые слова
- Интервалы и тайм-ауты
- Использование javascript для получения / установки пользовательских переменных CSS
- история
- Как заставить итератор использоваться внутри функции асинхронного обратного вызова
- карта
- Классы
- Комментарии
- Контекст (это)
- Литералы шаблонов
- локализация
- Манипуляция данными
- Массивы
- Методы модуляции
- Модалы — подсказки
- Модули
- Назначение деструктуризации
- наследование
- обещания
- Обнаружение браузера
- Обработка ошибок
- Объект Navigator
- Объекты
- Объем
- Объявления и задания
- Операции сравнения
- Оптимизация звонков
- отладка
- Оценка JavaScript
- Переменное принуждение / преобразование
- Переменные JavaScript
- Перечисления
- Печенье
- Побитовые операторы
- Побитовые операторы — примеры реального мира (фрагменты)
- Поведенческие шаблоны проектирования
- полномочие
- получать
- Пользовательские элементы
- Последовательности выхода
- Приставка
- Проблемы с безопасностью
- Пространства имен
- Прототипы, объекты
- Рабочие
- Регулярные выражения
- Свободный API
- Сети и Getters
- Символы
- События
- События, отправленные сервером
- Советы по повышению производительности
- Создание шаблонов проектирования
- Спецификация (модель объекта браузера)
- Сравнение даты
- Строгий режим
- Струны
- Та же политика происхождения и перекрестная связь
- Тильда ~
- Типы данных в Javascript
- Унарные операторы
- условия
- Файловый API, Blobs и FileReaders
- функции
- Функции конструктора
- Функции стрелки
- Функциональный JavaScript
- Цепочка метода
- Цикл событий
- экран
- Эффективность памяти
How to go from Blob to ArrayBuffer
You can use FileReader to read the Blob as an ArrayBuffer .
var arrayBuffer; var fileReader = new FileReader(); fileReader.onload = function(event) < arrayBuffer = event.target.result; >; fileReader.readAsArrayBuffer(blob);
// ArrayBuffer -> Blob var uint8Array = new Uint8Array([1, 2, 3]); var arrayBuffer = uint8Array.buffer; var blob = new Blob([arrayBuffer]); // Blob -> ArrayBuffer var uint8ArrayNew = null; var arrayBufferNew = null; var fileReader = new FileReader(); fileReader.onload = function(event) < arrayBufferNew = event.target.result; uint8ArrayNew = new Uint8Array(arrayBufferNew); // warn if read values are not the same as the original values // arrayEqual from: http://stackoverflow.com/questions/3115982/how-to-check-javascript-array-equals function arrayEqual(a, b) < return !(a; if (arrayBufferNew.byteLength !== arrayBuffer.byteLength) // should be 3 console.warn("ArrayBuffer byteLength does not match"); if (arrayEqual(uint8ArrayNew, uint8Array) !== true) // should be [1,2,3] console.warn("Uint8Array does not match"); >; fileReader.readAsArrayBuffer(blob); fileReader.result; // also accessible this way once the blob has been read
This was tested out in the console of Chrome 27—69, Firefox 20—60, and Safari 6—11.
Here’s also a live demonstration which you can play with: https://jsfiddle.net/potatosalad/FbaM6/
Update 2018-06-23: Thanks to Klaus Klein for the tip about event.target.result versus this.result
- https://developer.mozilla.org/en-US/docs/Web/API/FileReader#readAsArrayBuffer()
- https://www.w3.org/TR/FileAPI/#dfn-readAsArrayBuffer
Or you can use the fetch API
fetch(URL.createObjectURL(myBlob)).then(res => res.arrayBuffer())
I don’t know what the performance difference is, and this will show up on your network tab in DevTools as well.
Just to complement Mr @potatosalad answer.
You don’t actually need to access the function scope to get the result on the onload callback, you can freely do the following on the event parameter:
var arrayBuffer; var fileReader = new FileReader(); fileReader.onload = function(event) < arrayBuffer = event.target.result; >; fileReader.readAsArrayBuffer(blob);
Why this is better? Because then we may use arrow function without losing the context
var fileReader = new FileReader(); fileReader.onload = (event) => < this.externalScopeVariable = event.target.result; >; fileReader.readAsArrayBuffer(blob);
The Response API consumes a (immutable) Blob from which the data can be retrieved in several ways. The OP only asked for ArrayBuffer , and here’s a demonstration of it.
var blob = GetABlobSomehow(); // NOTE: you will need to wrap this up in a async block first. /* Use the await keyword to wait for the Promise to resolve */ await new Response(blob).arrayBuffer(); //=>
alternatively you could use this:
new Response(blob).arrayBuffer() .then(/* */);
Note: This API isn’t compatible with older (ancient) browsers so take a look to the Browser Compatibility Table to be on the safe side 😉