JSでバイナリを扱うことへの理解とメモ

ちょいちょい使うことがあるバイナリ操作処理だけど、イマイチ用語と用途が整理できていないのでメモ

背景

HTML5からバイナリが使えて便利最高!みたいな情報多いけど何が便利になってるのかよくわからない。
昔と比べてどう便利になったのかもふまえて整理してみる。

ゴール

JSでバイナリを使うことの利便性を享受できるようになる

まずバイナリが扱えるようになると何が嬉しいのか?

つーかバイナリって何?!

以下wikipedia引用

バイナリ(またはバイナリー:binary)とは、2進数のこと。 テキスト形式(文字データ)以外のデータ形式全般を指したり、コンピュータが処理・記憶するために2進化されたファイル(バイナリファイル)、またはその内部表現の形式(バイナリデータ、バイナリ形式)のことを指すのに用いられる。

つまり人間が読めないコンピューターだけが扱えるデータ形式

JSでバイナリが扱えなかった時代

  • バイナリを扱うためのAPIがなかったので、formタグでinput type=”file”を選択して送信するぐらいしかできなかった。
  • CSVやXML、画像ファイルなどのバイナリファイルはサーバー側に送って何かしらの処理を行っていた。

バイナリが扱えるようになった時代

  • HTML5以降にはいったFILE apiを使うことにより、バイナリの読み書きが行えるようになり、クライアント側だけで完結する処理が作れるようになった。
  • 画像をアップロードする前の画像をリサイズして送信したりとか、非同期で送信したりとか、アップロードするまえの画像をbase64エンコードしてimgタグに表示したりとかできて便利になった。

APIの種類と用途

Blob

  • バイナリデータを保持( immutable な生データ )
  • 値を取り出し不可( FileReaderやxhrなどを使用して中身をとりだせる)
  • サイズの確認や切り出しは可能(Blob.prototype.slice や Blob.prototype.size)
1
2
3
4
5
6
7
8
var req = new XMLHttpRequest();
req.open("GET", "https://i.imgur.com/rjI42fW.png", true);

req.onload = function(e) {
var blob = e.target.response; // これがBlob
};

req.send();

File

  • input type=”file”のファイル選択時にラップされるオブジェクト
  • Blobを継承している
  • Blobにファイル名や最終更新日の情報が追加されたもの( { name:String, lastModifiedDate:Date } )
    • ユーザーのシステム上のファイルをサポートするための機能を拡張
1
2
3
4
5
6
7
8
9
10
11
<input type="file" id="local_file">

input.onchange = function (event){
var input = event.target;
var file_list = input.files; // これはFileList
var file = file_list[0]; // これがFile

console.log(file.name);
console.log(file.lastModifiedDate);
};
</script>

ArrayBuffer

  • 物理メモリの領域(バッファ)を確保するためのクラス
  • バッファに対する操作はできない
    • バイト数取得と既存のバッファからあらたなバッファを作ったりしかできない
  • エンディアン方式がCPU依存
    • リトルエンディアンかビックエンディアンかを意識する必要がある
1
2
3
var buffer = new ArrayBuffer(12);

console.log(buffer.byteLength); // 12

Typed Array

  • 型付き配列
  • 型を指定してバッファから配列を生成
  • 「高速に」読み書きできる
  • 種類
    • Uint8Array
    • Uint16Array
    • Uint32Array
1
2
3
4
5
new Uint8Array([ (2 ** 8) -1 , 2, 3])
> Uint8Array(3) [255, 2, 3]

new Uint16Array([( 2 **16) - 1, 2, 3])
> Uint16Array (3) [65535, 2, 3]

DataView

  • TypedArrayよりも高機能なバッファ操作用クラス
  • ArrayBufferのエンディアン方式の差を吸収してくれる
    • リトルエンディアンかビックエンディアンかを意識する必要がない
1
2
3
4
var buffer = new ArrayBuffer(12);
var dataview = new DataView( buffer );

console.log(dataview);

BinaryString と DataURI と BlobURL

1
2
こういう形式のやつ
/9j/4AA~~~~~

DataURI

  • 画像のリソースをURIで表現できる
  • BinaryStringなのでサイズが1.3倍になる。。。
  • テキスト情報にバイナリデータをうめこめる(imgタグにうめこめる)
  • data: スキームが先頭についている URL
1
2
こういう形式のやつ
data:image/jpeg;base64,/9j/4AA~~~~~

FileReader使うと取得できる

1
2
3
4
5
6
7
8
9
10
11
12
<input type="file" id="local_file">

<script>
document.getElementById("local_file").onchange = function(event) {
var input = event.target;
var reader = new FileReader();
reader.onload = function(){
var dataURL = reader.result; // これがDataURI
   };
  reader.readAsDataURL(input.files[0]);
};
</script>

↓imgタグに埋め込めば画像も表示できる

BlobURL

  • 画像のリソースをURIで表現できる
  • セッション内でユニークなURIを生成する
  • DataURIとちがってリソースへのポインター的な扱いになるからメモリにやさしい
1
2
こういう形式のやつ
blob:http://kuniiskywalker.github.io/f6ea8265-610f-4fbe-abfa-335f13cfe34c

createObjectURLでURIを取得

1
2
3
var blob = new Blob( ["文字列テスト"] , {type: "text/plain"} );
var blob_url = URL.createObjectURL(blob); // これがBlobURL
console.log(blob_url); // blob:http://kuniiskywalker.github.io/f6ea8265-610f-4fbe-abfa-335f13cfe34c

まとめ

クライアントサイドでのオフライン対応が充実していく背景には、じつはこういった便利APIを知らず知らずのうちに使っていたことを改めて認識できた。
サーバーで仕事をさせるかクライアントで仕事をさせるかは、通信時のデータ転送量をとるか端末のCPUコストをとるか、要件次第な感じ。