Szukaj…
Uwagi
Tablice maszynowe zostały pierwotnie określone w szkicu redaktora Khronos , a następnie znormalizowane w ECMAScript 6 §24 i §22.2 .
Obiekty BLOB są określone przez roboczą wersję roboczą interfejsu API pliku W3C .
Konwertowanie między obiektami BLOB i ArrayBuffers
JavaScript ma dwa podstawowe sposoby reprezentowania danych binarnych w przeglądarce. ArrayBuffers / TypedArrays zawierają zmienne (choć wciąż o stałej długości) dane binarne, którymi można bezpośrednio manipulować. Obiekty blob zawierają niezmienne dane binarne, do których można uzyskać dostęp tylko poprzez asynchroniczny interfejs pliku.
Konwertuj obiekt Blob
na ArrayBuffer
(asynchroniczny)
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);
Konwertuj obiekt Blob
do ArrayBuffer
za pomocą Promise
(asynchronicznie)
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.");
});
Konwertuj ArrayBuffer
lub tablicę wpisaną na obiekt Blob
var array = new Uint8Array([0x04, 0x06, 0x07, 0x08]);
var blob = new Blob([array]);
Manipulowanie ArrayBuffers za pomocą DataViews
DataViews zapewniają metody odczytu i zapisu poszczególnych wartości z ArrayBuffer, zamiast przeglądania całej rzeczy jako tablicy jednego typu. Tutaj ustawiamy dwa bajty osobno, a następnie interpretujemy je razem jako 16-bitową liczbę całkowitą bez znaku, najpierw big-endian, a następnie 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
Tworzenie tablicy TypedArray z ciągu 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);
}
Korzystanie z tablic TypedArrays
TypedArrays to zestaw typów zapewniających różne widoki na zmienne binarne ArrayBuffers o stałej długości. W większości zachowują się jak tablice, które wymuszają przypisanie wszystkich wartości do danego typu liczbowego. Można przekazać instancję ArrayBuffer do konstruktora TypedArray, aby utworzyć nowy widok jego danych.
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 można kopiować przy użyciu metody .slice(...)
, bezpośrednio lub poprzez widok 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]
Uzyskiwanie binarnej reprezentacji pliku obrazu
Ten przykład jest inspirowany tym pytaniem .
Zakładamy, że wiesz, jak załadować plik za pomocą interfejsu API plików .
// 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
Teraz wykonujemy faktyczną konwersję danych pliku na 1 i 0 za pomocą 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
umożliwia odczyt / zapis danych numerycznych; getInt8
konwertuje dane z pozycji bajtu - tutaj 0
, przekazywana wartość - w ArrayBuffer
na 8-bitową reprezentację liczb całkowitych ze ArrayBuffer
, a toString(2)
konwertuje 8-bitową liczbę całkowitą na format reprezentacji binarnej (tj. ciąg 1 i 0).
Pliki są zapisywane jako bajty. Wartość przesunięcia „magicznego” jest uzyskiwana przez zauważenie, że bierzemy pliki przechowywane jako bajty, tj. Jako 8-bitowe liczby całkowite i odczytujemy je w 8-bitowej reprezentacji liczb całkowitych. Gdybyśmy próbowali odczytać nasze zapisane bajty (tj. 8 bitów) na 32-bitowe liczby całkowite, zauważylibyśmy, że 32/8 = 4 to liczba przestrzeni bajtów, która jest naszą wartością przesunięcia bajtu.
W przypadku tego zadania DataView
ma nadmiar. Są one zwykle stosowane w przypadkach, w których napotyka się endianizm lub niejednorodność danych (np. Podczas odczytywania plików PDF, które mają nagłówki zakodowane w różnych bazach i chcielibyśmy w sposób znaczący wyodrębnić tę wartość). Ponieważ chcemy tylko reprezentacji tekstowej, nie dbamy o heterogeniczność, ponieważ nigdy nie ma takiej potrzeby
O wiele lepsze - i krótsze - rozwiązanie można znaleźć, stosując UInt8Array
typu UInt8Array
, która traktuje cały ArrayBuffer
jako złożony z 8-bitowych liczb całkowitych bez znaku:
function ArrayBufferToBinary(buffer) {
var uint8 = new Uint8Array(buffer);
return uint8.reduce((binary, uint8) => binary + uint8.toString(2), "");
}
Iterowanie po tablicy Bufor
Aby w wygodny sposób iterować przez arrayBuffer, możesz utworzyć prosty iterator, który implementuje metody DataView
pod maską:
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;
});
Następnie możesz utworzyć iterator taki:
var cursor = new ArrayBufferCursor(arrayBuffer);
Możesz użyć hasNext
aby sprawdzić, czy są jeszcze elementy
for(;cursor.hasNext();) {
// There's still items to process
}
Możesz użyć next
metody, aby przyjąć następną wartość:
var nextValue = cursor.next('Float');
Przy takim iteratorze pisanie własnego parsera do przetwarzania danych binarnych staje się dość łatwe.