メモリとバイナリデータの基礎
まず、コンピュータメモリの基本的な概念を理解することが重要です。16進数では1桁が4ビットを表すため、0xFは1111に相当し、0xFFは8ビット(1バイト)になります。つまり、2桁の16進数が1バイトを表します。
例えば、8バイトのメモリ領域を確保し、所有するビットをすべて0で初期化すると、以下のようになります:
00 00 00 00 00 00 00 00
データ型のサイズ
メモリにアクセスする際の数据类型は、偏移(オフセット)バイト数决定了します:
- BYTE(バイト):1バイト、偏移1
- WORD(ワード):2バイト、偏移2
- DWORD(ダブルワード):4バイト、偏移4
- QWORD(クアッドワード):8バイト、偏移8
JavaScriptのTypedArrayでは、Int8Arrayは8ビット(1バイト)型であり、偏移値は1バイトです。同様に、Int16Arrayは16ビット(2バイト)型で、偏移値は2バイトです。
バイト順序(エンディアン)
計算機にはデータを保存する方法endelawareつの異なる方式があります:
- リトルエンディアン:データの低位がアドレスの低位に保存される
- ビッグエンディアン:データの高位がアドレスの低位に保存される
例として、4バイトのメモリ空間(アドレス0x100-0x103)に0x0000000Aを格納する場合を考えます:
// リトルエンディアンの場合
アドレス: 0x100 0x101 0x102 0x103
データ: 0x0A 0x00 0x00 0x00
実際に確認してみましょう:
let buffer = new ArrayBuffer(4);
let view = new Uint32Array(buffer);
view[0] = 0xA;
console.log(buffer);
// 表示結果
// [[Int8Array]]: Int8Array(4) [10, 0, 0, 0]
// [[Int16Array]]: Int16Array(2) [10, 0]
// [[Int32Array]]: Int32Array [10]
// [[Uint8Array]]: Uint8Array(4) [10, 0, 0, 0]
// byteLength: 4
Int32Arrayでは0x0000000Aと表示され、Int8Arrayでは0x0A000000のように表示されます。これはリトルエンディアン方式でデータが 저장されているためです。
別の例を見てみましょう:
let buffer = new ArrayBuffer(4);
let view = new Int8Array(buffer);
view[1] = 0x01; // 0A 01 00 00
console.log(view);
// Int8Array(4) [0, 1, 0, 0]
let intView = new Uint32Array(buffer);
console.log(intView[0]); // 266 (0x010A)
byteLengthとlengthの違いを理解することは重要です:
- byteLength:バッファのサイズ(バイト単位)。不変。
- length:TypedArrayの要素数。数据类型によって変化する。
let buffer = new ArrayBuffer(8);
let int8 = new Int8Array(buffer);
console.log(int8.byteLength, int8.length); // 8, 8
let int16 = new Int16Array(buffer);
console.log(int16.byteLength, int16.length); // 8, 4
let int32 = new Int32Array(buffer);
console.log(int32.byteLength, int32.length); // 8, 2
ArrayBuffer API
ArrayBufferは固定長のバイナリデータを表現しますが、直接操作することはできません。操作にはTypedArrayまたはDataViewを使用する必要があります。
// 8バイトのバッファを確保
let buffer = new ArrayBuffer(8);
console.log(buffer.byteLength); // 8
// DataViewがビューかどうかを確認
console.log(ArrayBuffer.isView(new DataView(buffer))); // true
// Int32Arrayで参照(4バイト × 2 = 8バイト)
let view = new Int32Array(buffer);
console.log(view);
// 値を設定
view[0] = 0xFFFF; // 65535
view[1] = 0xFFFE; // 65534
console.log(view); // Int32Array(2) [65535, 65534]
TypedArray(型付き配列)
TypedArrayにはいくつかのコンストラクタがあります:
// 長さから作成
let arr1 = new Int32Array(4); // 4要素の配列(16バイト)
// 既存のバッファから作成
let buffer = new ArrayBuffer(8);
let arr2 = new Int16Array(buffer);
// バッファ、オフセット、长度から作成
let arr3 = new Int8Array(buffer, 2, 3); // 2バイト偏移、3要素
// 反復可能オブジェクトから作成
let arr4 = new Uint8Array([1, 2, 3, 4]);
代表的なTypedArrayの種類:
- 8ビット整数:Int8Array、Uint8Array、Uint8ClampedArray
- 16ビット整数:Int16Array、Uint16Array
- 32ビット整数:Int32Array、Uint32Array
- 浮動小数点数:Float32Array、Float64Array
要素へのアクセス:
let buffer = new ArrayBuffer(8);
let arr = new Int8Array(buffer);
for (let i = 0; i < buffer.byteLength; i++) {
arr[i] = i * 2;
}
console.log(arr); // Int8Array(8) [0, 2, 4, 6, 8, 10, 12, 14]
console.log(arr.length); // 8
console.log(arr[arr.length - 1]); // 14
// 偏移付で作成
let partial = new Int8Array(buffer, 2);
console.log(partial); // Int8Array(6) [4, 6, 8, 10, 12, 14]
DataView
DataViewは、異なるデータ型を同じバッファから読み書きできる低レベルインターフェースです。プラットフォームのバイト順序を意識せずに操作できる点が特徴です。
let buffer = new ArrayBuffer(8);
let dataView = new DataView(buffer, 0, 8);
// 値の書き込み(リトルエンディアン)
dataView.setInt16(0, 14, true);
console.log(dataView.getInt16(0, true)); // 14
console.log(dataView.getInt8(0)); // 14 (0x0E)
console.log(dataView.getInt32(0, true)); // 14
// 異なるオフセットでの操作
dataView.setUint8(2, 0xFF);
console.log(dataView.getUint8(2)); // 255
// プロパティ
console.log(dataView.buffer); // ArrayBuffer
console.log(dataView.byteLength); // 8
console.log(dataView.byteOffset); // 0
主要なメソッド:
- getInt8, getUint8, getInt16, getUint16, getInt32, getUint32, getFloat32, getFloat64
- setInt8, setUint8, setInt16, setUint16, setInt32, setUint32, setFloat32, setFloat64
各メソッドの3番目の引数には、littleEndianフラグを指定できます(trueでリトルエンディアン)。
バイト順序の検出
実行環境のバイト順序を検出する必要がある場合があります:
function isLittleEndian() {
let testBuffer = new ArrayBuffer(2);
new DataView(testBuffer).setInt16(0, 1, true);
let testArray = new Int16Array(testBuffer);
return testArray[0] === 1;
}
console.log("リトルエンディアン:", isLittleEndian()); // trueまたはfalse
Node.jsのBufferとの互換性
ブラウザ環境でNode.js同様のBuffer APIを使用したい場合は、bufferライブラリ可以利用できます:
<script src="https://bundle.run/buffer@5.6.0"></script>
<script>
const { Buffer } = buffer;
let buf = Buffer.alloc(4);
buf.writeInt32LE(0x0A, 0);
console.log(buf);
console.log(buf.readInt32LE().toString(16));
</script>
まとめ
ArrayBufferはバイナリデータの的基础となるオブジェクトであり、TypedArrayとDataViewを使用して効果的に操作できます。バイト順序 мясо正しく理解し、適切なAPIを選択することが重要です。