HTML5のJavaScriptでバイナリファイルを扱う(その2)

コードの解説。

jQueryのイベントオブジェクトからファイルデータにアクセスするためのおまじない。

jQuery.event.props.push('dataTransfer');

PCからファイルがドロップされたときの処理

$("#file").bind("drop", function(event){
    // ドロップされたファイルは、eventのdataTransferプロパティの
    // fileプロパティに配列(例によってArrayではない)に格納されている
    viewFileContent(event.dataTransfer.file[0]);
}

ファイルの中身を読み取る処理

function viewFileContent(file) {

    // ファイル読み込みオブジェクトが実装されているかどうか?
  if (!window.FileReader) {
        console.log("ご利用のブラウザはファイル読み込みをサポートしていません")
        return;
    }

    var fr = new FileReader();
    
    // バイナリ読み込みメソッドが実装されているかどうか?
    if (!fr.readAsArrayBuffer) {
        console.log("ご利用のブラウザはバイナリ読み込みをサポートしていません")
        return;
    }

    // ファイル読み込み時のイベントを設定
    fr.onload = function(event){
        // ファイルのデータが入ったArrayBufferオブジェクトを取得
        var data = event.target.result;

        // Uint8Arrayは、ArrayBufferのデータに符号あり16ビット整数としてアクセスするためのラッパー
        // 普通に配列のようにアクセスできるが、
        // 例によってJavaScriptのArrayオブジェクトではないので注意
        var buf = new Uint8Array(data);

        // read
        console.log(buf[0]);
        console.log(buf[1]);

        // write
        buf[0] = 2;
        buf[1] = 16;
        
        // あとは好きなように処理すべし。重そうならWebWorkerに任せよう
    };

    // ファイル読み込みエラー時の処理(read権限のないファイルとか)
    fr.onerror = function(error) {
        console.log(error);
    };
        
    // ファイルデータへのアクセス開始。ArrayBufferオブジェクトとしてデータを取得する。
    fr.readAsArrayBuffer(file);
}

ファイル読み込みも、JavaScriptではおなじみのイベント駆動型の処理で行う。

ArrayBufferView

Uint8Arrayという謎のオブジェクトは、ArrayBufferのデータを操作するために用意されたArrayBufferViewのひとつ。Uint8Arrayを用いると、ArrayBufferのデータを8ビット符号なし整数として読み書きできる。

ArrayBufferViewには以下のオブジェクトがある。

  • Int8Array
  • Uint8Array
  • Int16Array
  • Uint16Array
  • Int32Array
  • Uint32Array
  • Float32Array
  • Float64Array

16、32、64ではバイトオーダがCPUネイティブになる(Intel CPUならリトルエンディアン)らしいので、Webで使うのは難しいかもしれない。

DataView

DataViewでは、インデックス指定アクセスはできないが、バイトオーダや符号を指定してデータを読み出すメソッドが用意されている。

var dataView = new DataView(data);

// オフセット0からリトルエンディアンで、16ビットを符号なしの数値として取得
dataView.getUint16(0, true);
// オフセット0からリトルエンディアンで、16ビットを符号ありの数値として取得
dataView.getInt16(0, true);

// オフセット0からビッグエンディアンで、16ビットを符号なしの数値として取得
p(buf3.getUint16(0));
// オフセット0からビッグエンディアンで、16ビットを符号ありの数値として取得
p(buf3.getInt16(0));

ArrayBufferViewやDataViewは、ArrayBufferの参照を保持しているだけのビューなので、writeするとラップしているArrayBufferが書き換えられる。