JavaScript

JavaScriptのDataView.getUint16():バイト順を指定して2バイトの整数を読む

この記事でわかること

DataView.getUint16()でバイナリの2バイトを整数として読む方法を解説。引数・戻り値、バイト順、ブラウザーとNode.jsでの実行手順、範囲外の例外や部分データの扱いを学べます。

目的:バイト列から数値を取り出す

通信データやファイルのヘッダーでは、件数や識別番号が2バイトの整数で記録されることがあります。たとえば、16進数の0x01と0x02を受け取っても、文字列として連結するだけでは、その形式が表す数値を正しく取り出せません。

DataView.prototype.getUint16()は、指定位置から2バイトを読み、符号なし16ビット整数として返すメソッドです。読み取り順序も指定できるため、実行するコンピューターの都合ではなく、データ形式の仕様に合わせて解釈できます。MDNのgetUint16()リファレンス

この記事では、先頭2バイトが件数、続く2バイトが識別番号という架空のヘッダーを読みます。実ファイルやネットワークを使わず、入力データをコード内で用意するので、読み取り処理だけを試せます。

動作環境と実行方法

2026年11月7日時点で確認したMDNでは、getUint16()は広く利用可能な機能に分類され、2015年7月以降の主要ブラウザー間で利用できるとされています。現在のChrome、Edge、Firefox、Safariで使用できます。ただし、この日付は各製品の最初の対応バージョンを意味しません。MDNの対応状況

JavaScriptの組み込み機能なので、ブラウザーとNode.jsの両方で動作します。本文のNode.js側の対象は24系とし、導入時の最小バージョンは扱いません。外部パッケージやビルド処理は不要です。

ブラウザーで実行する

通常のページで開発者ツールを開き、Consoleに後述のJavaScriptコード全体を貼り付けて実行します。繰り返し実行できるよう、コードは即時実行関数で囲んであります。読み込むファイルやサーバーの準備は必要ありません。

Node.jsで実行する

Node.js 24系をインストールした環境で、コードをUTF-8のread-header.jsとして保存します。そのファイルがあるディレクトリーで、次のコマンドを実行してください。

Shell
node --version
node read-header.js

最初のコマンドでv24.から始まるバージョン表示を確認します。ファイル名をnodeに渡す実行方法は、Node.js公式のスクリプト実行ガイドに沿っています。

引数と戻り値を理解する

呼び出し方はview.getUint16(byteOffset, littleEndian)です。

  • byteOffsetは、DataViewの先頭から何バイト進んだ位置を読むかを指定します。最初の位置は0です。
  • littleEndianは省略可能です。trueならリトルエンディアン、falseまたは省略ならビッグエンディアンとして読みます。
  • 戻り値は0以上65535以下の整数で、JavaScriptの型はnumberです。

2バイトを読むため、開始位置だけが範囲内でも、次の1バイトが不足すればRangeErrorになります。開始位置を2の倍数にそろえる必要はなく、奇数位置からも読み取れます。MDNの引数・戻り値・例外

バイト順で値が変わる理由

ビッグエンディアンは、先にあるバイトを上位桁として扱います。0x01, 0x02なら、1 * 256 + 2で258です。リトルエンディアンでは同じ並びを2 * 256 + 1と解釈し、513になります。

これはデータを書いた側の仕様で決まります。結果がそれらしい数になるまでフラグを切り替える運用では、別の入力で誤読します。形式仕様にバイト順を明記し、コードでも引数を明示すると意図が残ります。MDNのDataViewとバイト順の説明

自己完結したコードでヘッダーを読む

次の例のpacketには、前後に読み取り対象外のバイトを置いています。headerは中央の4バイトだけを参照します。これにより、部分データを扱う際の開始位置と長さも確認できます。

JavaScript
(() => {
  function parseHeader(bytes) {
    if (!(bytes instanceof Uint8Array)) {
      throw new TypeError("入力はUint8Arrayにしてください");
    }
    if (bytes.byteLength !== 4) {
      throw new RangeError("ヘッダーは4バイト必要です");
    }

    const view = new DataView(
      bytes.buffer,
      bytes.byteOffset,
      bytes.byteLength
    );

    return {
      count: view.getUint16(0, false),
      id: view.getUint16(2, false)
    };
  }

  const packet = new Uint8Array([
    0xff,
    0x00, 0x03,
    0x01, 0x02,
    0xee
  ]);
  const header = packet.subarray(1, 5);
  const result = parseHeader(header);

  console.log(`件数: ${result.count}`);
  console.log(`識別番号: ${result.id}`);

  const view = new DataView(
    header.buffer,
    header.byteOffset,
    header.byteLength
  );
  console.log(`逆のバイト順: ${view.getUint16(2, true)}`);

  try {
    view.getUint16(3, false);
  } catch (error) {
    if (!(error instanceof RangeError)) throw error;
    console.log(`範囲外: ${error.name}`);
  }

  try {
    parseHeader(new Uint8Array([0x00]));
  } catch (error) {
    if (!(error instanceof RangeError)) throw error;
    console.log(`入力不正: ${error.message}`);
  }
})();

期待出力

CODE
件数: 3
識別番号: 258
逆のバイト順: 513
範囲外: RangeError
入力不正: ヘッダーは4バイト必要です

件数のバイト列は0x00, 0x03なので3、識別番号は0x01, 0x02なので258です。逆順で読んだ行だけは意図的に513を表示します。

この期待出力は公式仕様と数値計算に基づくもので、ここでコードを実機実行した結果ではありません。例外メッセージの環境差を避けるため、組み込み例外については名前だけを出力しています。

失敗例と制約

元のバッファー全体を読んでしまう

上のコードでnew DataView(header.buffer)とだけ書くと、読み取り範囲はheaderの4バイトではなく、元のpacket全体になります。その状態で位置0を読むと、対象外の0xffと次の0x00から65280を得てしまいます。

DataViewの生成には、元のバッファー内での開始位置と対象の長さを渡してください。一方、getUint16()に渡す位置は、生成したビューの先頭を基準にします。そこで再びbytes.byteOffsetを足す必要はありません。MDNのDataViewコンストラクター

Node.jsのBufferも、内部のArrayBufferの途中を参照する場合があります。Bufferからビューを作る場合にも、bufferだけでなくbyteOffsetとbyteLengthを引き継ぐことが重要です。Node.js公式のbuf.byteOffsetの説明

バイト不足と意味上の不正は別に検証する

例のview.getUint16(3, false)は、長さ4のビューから位置3と4を読もうとするため失敗します。通信途中のデータを扱うなら、必要な長さがそろってから解析してください。

また、読み取れた整数が業務上正しいとは限りません。件数の上限が100件なら、101は読み取り自体には成功しても受け付けるべきではありません。構造の検査と値の検査は分けて考えます。

この例の型チェックは、同じJavaScript実行領域で作ったUint8Arrayを対象にしています。別ウィンドウなど、異なる実行領域から渡された値の受け入れまで保証するものではありません。

同期処理と共有メモリーに注意する

getUint16()は同期的に数値を返すので、awaitは不要です。非同期のファイル取得や通信を組み合わせる場合は、取得完了を待ち、その取得失敗と解析失敗を呼び出し側で処理します。

DataViewは元データをコピーせず参照します。読み取り前に同じバッファーを書き換えれば、読む値も変わります。この例は固定長の通常のArrayBufferを対象にし、転送による切り離しや共有メモリーの並行更新は扱いません。

活用事例と実装を改善する次の一歩

独自通信形式の件数、バイナリファイルの形式番号、機器から届く16ビットの測定値など、2バイトの符号なし整数を読む場面に利用できます。負の値や65535を超える値を表すフィールドには、このメソッドをそのまま当てはめられません。

実装を育てるなら、まずデータ形式の各項目について、開始位置、必要バイト数、バイト順、許容値を書き出してください。その定義に合わせて読み取り位置を固定すると、データ形式が変わった際の修正箇所が明確になります。

追加の改善として、正常データだけでなく、1バイト不足した入力と上下限の入力も用意すると有効です。読み取り成功だけでは見落とす範囲チェックの不足を確認できるためです。

公式参考資料

  • MDN:DataViewは、バイト順を明示する理由の参考になります。
PREFERRED SOURCES

Googleの優先するニュース提供元にSEの部屋を追加

Googleで、いつも読みたい情報源を選べます。登録可否はGoogleの画面で確認できます。

Googleの設定画面で確認する 新しいタブで開きます

候補にSEの部屋が表示されない場合は、まだ追加できません。

y.
WRITTEN BY

y_ymo10

SEの部屋で、HTML・CSSからJavaScript・React・Next.jsまで、Web制作の開発ノートを公開しています。

ほかの開発ノートを読む →