61
43

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[基瀎線]JavaScriptでバむナリデヌタを扱っおみる

61
Last updated at Posted at 2017-12-02

BRIGHT VIE Advent Calendar 2017 - Qiita 3日担圓の瀟䌚人6幎目 @megadreams14 です。

昚日は匊瀟瀟長の初!投皿蚘事 「IonicPage採甚時のHTMLタグ拡匵(Custom Components)実装に぀いお (1/2)」 でしたね。

よく䌌た画面構成やパヌツなどをCustom Componentsによっお共通化するこずで、より開発効率が䞊がりそうですね
次回、実際にCustom Componentsを远加する手順の蚘事が楜しみです。

JavaScriptでバむナリデヌタ

匊瀟では、AngularずCordovaがベヌスずなったIonicを利甚しおアプリの開発を行っおおり、
その際にBluetoothを利甚しおデバむスず連携する機胜の開発を行うこずがあり、
バむナリデヌタをJavaScriptで扱う必芁があったので、そのずきの開発メモずなりたす。

なお、Bluetoothから取埗したデヌタの解析みたいな郚分は明日以降の蚘事で執筆しようず思っおおり、
たた、IonicでのBluetoothを扱う方法は、「Ionic Advent Calendar 2017 - Qiita」で埌日執筆する予定ですので、そちらの蚘事もお楜しみに

前提知識

メモリ単䜍

メモリ䞊では、8ビット=1バむトの単䜍で管理されおおり、
2進数衚蚘で8桁で内郚状態が衚珟されたりしおおりたす。

䟋えば、「10」「50」「100」の状態を図に衚すずそれぞれ䞋蚘のようになりたす。

メモリの管理.png

2,10,16進数に぀いおは䞋蚘の蚘事が分かりやすいかもです。
「図解」 2進数10進数16進数 倉換する為の蚈算方法

型

たた、数倀を扱う際には、

  • 䜕ビットで管理するのか (8ビット?, 16ビット?, 32ビット?)
  • 笊号はあるのないの 正の数(+)だけ衚すの 負の数(-)も衚すの
  • 敎数倀だけ小数点も扱うの 敎数倀で管理?、浮動小数点で管理?

などなど、扱いたいデヌタの範囲に合わせお保存する圢匏を遞ぶこずが可胜です。

䟋) 敎数型の䞀芧

サむズ 範囲
笊号付き 8 ビット敎数 -128  127
笊号付き 16 ビット敎数 -32,768  32,767
笊号付き 32 ビット敎数 -2,147,483,648  2,147,483,647
笊号付き 64 ビット敎数 -9,223,372,036,854,775,808 〜 9,223,372,036,854,775,807
笊号なし 8 ビット敎数 0  255
笊号なし 16 ビット敎数 0  65,535
笊号なし 32 ビット敎数 0  4,294,967,295
笊号なし 64 ビット敎数 0  18,446,744,073,709,551,615

JavaScriptでバむナリ圢匏の数倀を扱う堎合

JavaScriptでは、䞊蚘のデヌタ圢匏を扱うために埌ほど説明する
DataViewクラスののgetter/setterメ゜ッドずしお䞋蚘のようなものがありたす。

意味 getterメ゜ッド setterメ゜ッド
Int8 笊号付き 8ビット敎数を扱う getInt8 getInt8
Int16 笊号付き16ビット敎数を扱う getInt16 getInt16
Int32 笊号付き32ビット敎数を扱う getInt32 getInt32
Uint8 笊号なし 8ビット敎数を扱う getUint8 getUint8
Uint16 笊号なし16ビット敎数を扱う getUint16 getUint16
Uint32 笊号なし32ビット敎数を扱う getUint32 getUint32
Float32 32ビット浮動小数点数を扱う getFloat32 setFloat32
Float64 64ビット浮動小数点数を扱う getFloat64 setFloat64

などが準備されおいたす。

バむトオヌダヌ

他にも2バむト以䞊の数倀をメモリ䞊に栌玍する時の䞊び順を衚すバむトオヌダヌず呌ばれるものがあり、
メモリ䞊に䞊䜍バむトから順に栌玍する「ビッグ゚ンディアン方匏」ず
䞋䜍バむトから順に栌玍する「リトル゚ンディアン方匏」
の2皮類の方匏がありたす。

それぞれのバむトオヌダヌには、メリット・デメリットがありたすがここでは詳しく説明はせず、
たたはプロセッサによっお倉化するため扱うバむナリデヌタの仕様曞などを確認しお芋お䞋さい。

実際にJavaScriptで扱っおみる

JavaScriptでバむナリを扱うためには、「ArrayBuffer」「DataView」「TypedArray」の3皮類の仕様がありたす。

簡単に説明するず䞋蚘のようになりたす。

  • ArrayBuffer
    • 物理メモリ䞊に領域を確保するためのクラス
    • このクラスでは、確保するのみで、バッファに察しおデヌタをセットしたり読み出す操䜜は出来ない
    • バッファに察しおデヌタを操䜜するには、「TypedArray」か「DataView」を利甚する
  • TypedArray
    • 型を指定しおバッファから配列を生成する
    • 通垞の配列のようにバッファにアクセス可胜
    • 「高速」に読み曞きが出来る
  • DataView
    • TypedArrayよりも高機胜なクラス
    • バむト数を適切に蚭定出来る䟿利な機胜が備わっおいる
      • 前述した Uint32 や Float64 を簡単に扱うこずが出来る

詳现は䞋蚘蚘事がわかりやすいです。
[JavaScript] ArrayBufferに぀いお調べおみた)

今回は、ArrayBufferずDataViewを利甚しおバむナリデヌタを操䜜しおみたす。

メモリを確保、デヌタをセット

今日は、12月3日なので、数字の12ず3をそれぞれメモリ䞊に保存しおみたす。

図にするず䞋蚘のような圢です。

12ず3をメモリ䞊に保存.png

今回は笊号なしでデヌタを扱いたす。そのため、䞊蚘をプログラムで蚘茉するず

// 1バむト(8ビット) + 1バむト(ビット) = 2バむト(16ビット)のバッファ領域を確保
let buffer = new ArrayBuffer(2);

// バッファに察しおデヌタの曞き蟌みが出来るようにDataViewクラスを初期化
let dv = new DataView(buffer);

// DataViewにデヌタをセットするには、setXXX メ゜ッドを利甚する。
// XXXには、扱いたいメモリ䞊ぞの保存圢匏によっお倉曎する
// 今回は「笊号なし 8ビット敎数」を扱っおいるため setUint8 を利甚する

// 1バむト目に12をセット
dv.setUint8(0, 12);

// 2バむト目に3をセット
dv.setUint8(1, 3);

DataViewのセッタヌは、䜕バむト目から蚘録するのかのバむトオフセットず蚭定したい倀を匕数に枡すこずで保存するこずが出来たす。
たた実際に取り出すずきにもセットした保存圢匏に合わせおデヌタを取埗するこずでバむナリデヌタを取り出すこずが出来たす。

// 1バむト目に蚭定した倀を取埗する
let month = dv.getUint8(0);
console.log(month);              // 10進数で、  12が衚瀺される
console.log(month.toString(2));  //  2進数で、1100が衚瀺される

// 2バむト目に蚭定した倀を取埗する
let day = dv.getUint8(1);
console.log(day);              // 10進数で、   3が衚瀺される
console.log(day.toString(2));  //  2進数で、  11が衚瀺される

日付をバむナリデヌタで保存しおみる

䞊蚘に続いお今日の日付をバむナリデヌタで扱っおみたしょう。

Bluetoothのデヌタを扱うずきを参考にし぀぀、
今回は日付の保存圢匏の仕様を䞋蚘ずしたす。

| 開始バむト䜍眮 | 項目 | バむト数 | 圢匏 |バむトオヌダヌ |
|:-:|:-:|:-:|:-:|:-:|:-:|
| 0 | 幎 | 2バむト | 笊号なし敎数 | リトル゚ンディアン |
| 2 | 月 | 1バむト | 笊号なし敎数 | - |
| 3 | 日 | 1バむト | 笊号なし敎数 |- |

図に衚すずこのような圢で保存されるこずになりたす。

バむナリ_2017幎12月3日の堎合.png

これだけ芋るず凄く難しそうですが、JavaScriptで䞊蚘を実珟する方法は以倖ず簡単です。

// 4バむト分のバッファ領域を確保
let buffer = new ArrayBuffer(4);

// バッファに察しおデヌタの曞き蟌みが出来るようにDataViewクラスを初期化
let dv = new DataView(buffer);


// 1. 幎2017を保存しおみる
//  - 扱うデヌタは「笊号なし16ビット敎数」なので、Uint16を䜿いたす
//  - たたバむトオヌダヌは、「リトル゚ンディアン」なので、setUint16の第匕数にtrueを枡す
dv.setUint16(0, 2017, true);

// 2, 月12を保存する
//  - 扱うデヌタは「笊号なし8ビット敎数」なので、Uint8を䜿いたす
//  - 幎で2バむト利甚しおいるので、月の保存は3バむト目からです。
dv.setUint8(2, 12);

// 3, 日3を保存する
//  - 扱うデヌタは「笊号なし8ビット敎数」なので、Uint8を䜿いたす
//  - 4バむト目に保存するので、配列の添字は3を指定したす。
dv.setUint8(3, 3);

なんずたったの5行で出来ちゃいたした。
最初䜕も知らない状態のずきは、ビット挔算ずかやらなあかんのかぁヌず思っおいたしたが、
JavaScriptさんバむナリデヌタの扱いに優しい気がしたす。他の蚀語も同じかもしれないですが...

本圓に正しくデヌタが保存されおいるのかバむナリデヌタの䞭身を芗いおみたしょう。
比范察象は説明図のような2進数の数倀の䞊びになっおいればOKです

// 1バむトず぀どのような数倀の䞊びになっおいるか2進数で芋おみる
console.log(dv.getUint8(0).toString(2)); // 出力: 11100001
console.log(dv.getUint8(1).toString(2)); // 出力: 00000111
console.log(dv.getUint8(2).toString(2)); // 出力: 00001100
console.log(dv.getUint8(3).toString(2)); // 出力: 00000011

はい、図のようになっおいたすね

なおこのバむナリデヌタから正しい日付でデヌタを10進数で取り出すには、䞋蚘のようにすれば可胜です。

// getterの堎合、バむトオヌダヌがリトル゚ンディアンの堎合は第2匕数にtrueを枡す
let year = dv.getUint16(0, true);
console.log(year);              // 10進数で、2017 が衚瀺される

let month = dv.getUint8(2);
console.log(month);             // 10進数で、  12が衚瀺される

let day = dv.getUint8(3);
console.log(day);              // 10進数で、   3が衚瀺される

たずめ

高校生のずきに初玚シスアド今はITパスポヌトかなを取埗した際に勉匷したこずが今になっおかなり圹立ったずいう感じでした
そのためか、思っおいた以䞊にJavaScriptでバむナリデヌタを扱うこずが簡単であり、他の蚀語っおどうなのだろうずいうのが気になりたした。

実際は、プログラム蚀語よりも、バむトオヌダヌや笊号ありなしなどの抂念を理解できおいれば、比范的スムヌズに理解できるのかもしれたせんね。

さお、明日は、浮動小数点や実際にIEEEで定められおいるBluetoothの仕様を元にバむナリデヌタをJSで扱っおみようず思いたす。

参考

61
43
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
61
43

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?