os0x(Shogo Ohta), 2010-12-16
File API
ローカルファイルを直接(サーバーサイドを介さず)(テキストやBlobとして)読み取ることができるAPI
という認識が多いかも?
正確には、(2010年12月時点で)File APIは3つの仕様に分かれています
というわけで、今日はFile WriterとFile Directories and System(以下、File System API)の紹介です
File Writerはファイルを作る・書きこむAPI
そのままですね。
File System APIってなんでしょう?
This specification defines an API to navigate file system hierarchies, and defines a means by which a user agent may expose sandboxed sections of a user's local filesystem to web applications. It builds on [FILE-WRITER], which in turn built on [FILE-API], each adding a different kind of functionality.
この仕様はファイルシステム階層を操作するAPIを定義し、またユーザーエージェント(ウェブブラウザ)がウェブアプリケーション向けにユーザーのローカルファイルシステムを安全に解放する方法を定義します。
大雑把に言えば、ウェブアプリからハードディスク(に限らない記憶領域)にファイルを安全に保存・参照できるようにするための仕様です
例えばメールのように古いデータはほとんど使わないけど一応取っておきたい場合に、圧縮してローカルに保存しておくことができます
Picasa・iTunesのような画像・音声・動画の管理アプリケーションをブラウザ内で完結できます
データ型など、これまでのWebAPIにはなかった概念がいろいろ出てくるので、ざっくり整理していきます。
File APIではバイナリデータを扱います。バイナリデータを従来のArrayで扱うには非効率なので、BlobとTyped Arrayが導入されました。
Typed ArrayはWebGLから派生して、File APIやWeb SocketにXMLHttpRequest Level 2などと関連した仕様として策定が進んでいます
いわゆる型付き配列の1種
符号無しの整数のUint8Array・Uint16Array・Uint32Array、符号付き整数のInt8Array・Int16Array・Int32Array、浮動小数点数のFloat32Array・Float64Arrayなどの種類があります
当然ながら普通の配列より高速にアクセスできて、しかもsliceすることで巨大なデータの一部分だけを効率的に処理することも可能になります
ただ、ECMAScript側でもバイナリデータを扱うためのAPIが提案されているので、このあたりの仕様は今後も大きな動きがあるかもしれません strawman:binary_data [ES Wiki]
Typed ArrayはWebGL由来なので、WebGLが有効な環境、つまりChrome(stable版の場合は about:flags での設定が必要)やFirefox4(about:configで設定)などで既に使うことができます
Typed Array の初期化
var uint_array = new Uint8Array(1024); console.log(uint_array.buffer instanceof ArrayBuffer);
Uint8ArrayなどはArrayBufferViewインターフェースを継承しており、そのインスタンスはbufferプロパティを持っています
bufferプロパティはArrayBufferを継承したオブジェクトです
もちろん、自分でTyped Arrayを初期化することは多くないでしょう
XMLHttpRequestとArrayBuffer
var x = new XMLHttpRequest();
x.open('get','img/file.jpg');
x.responseType='arraybuffer';
// x.responseType='blob';
x.onload=function(r){
console.log(x.response instanceof ArrayBuffer);
};
x.send();
XMLHttpRequest(Level 2のEditor's Draft)にresponseTypeが追加され、text、blob、documentを指定できます(2010年11月時点でWebKitはblobではなくarraybufferで実装している)
responseTypeにblobを指定すると、responseでBlobを取得できます
FileAPIで定義されているバイナリデータ向けインターフェース。Binary Large Object。
FileAPIではBlobはローカルファイルからFileReaderで読み取るだけだったが、File Writer APIではBlobBuilderを使って作ることができるようになりました(Chromeではプリフィックス付きのWebKitBlobBuilder)
var bb = new (window.BlobBuilder || window.WebKitBlobBuilder)();
bb.append('sample');
var blob = bb.getBlob();
appendできるのは、Blob、ArrayBuffer、文字列のどれか
var x = new XMLHttpRequest();
x.open('get','img/file.jpg');
x.responseType='arraybuffer';
x.onload=function(r){
/* BlobBuilderでBlobに変換 今回はWebKit決め打ち */
var bb = new WebKitBlobBuilder();
bb.append(x.response);
var blob = bb.getBlob();
/* FileReaderでBlobの読み込み */
var fr = new FileReader();
/* 先頭256バイトをバイナリ文字列として */
fr.readAsBinaryString(blob.webkitSlice(0, 256));
fr.onload = function(){
output.textContent = fr.result;
};
};
x.send();
まず、(window.)requestFileSystemで初期化(一時的なデータ(TEMPORARY)か永続的なデータ(PERSISTENT)かどうかと、容量を指定)します
初期化したFileSystemオブジェクトにはrootプロパティがあり、これを基点にgetFileメソッドでファイルを参照し、その中身を作ったり、中身を読み出したりすることができます
ファイルの中身を作ったり、読み出したりする部分は前述のFile API・File Writer APIに依存します。
webkitRequestFileSystem(PERSISTENT,
1024 * 1024,
function(fs) {
/* コールバックでFileSystem
オブジェクトを受け取る */
/* getDirectoryにcreate: true
オプションでフォルダを作る */
fs.root.getDirectory("data", {
create: true
},
function(dir){
/* getFileにcreate: true
オプションでファイルを作る */
dir.getFile("tempfile.txt", {
create: true
},
function (file) {
console.log(fs);
console.log(dir);
console.log(file);
temp_file = file;
}
);
}
);
});
temp_file.createWriter(function(writer) {
console.log(writer);/* FileWriterオブジェクト*/
writer.onwrite = function(e) {
console.log('writer completed.');
};
writer.onerror = function(e) {
console.log('write failed: ' + e);
};
var bb = new WebKitBlobBuilder();
bb.append('HTML5!\n');
bb.append('日本語');
writer.write(bb.getBlob('text/plain'));
});
なお、Chromeでは、Windows7の場合
%USERPROFILE%\AppData\Local\Google\Chrome\User Data\Default\FileSystemに実際に保存されています。
FileSystem APIで保存されているファイルは、(window.)saveAsでローカルに保存し直す(いわゆるダウンロード)こともできます(WebKitでも未実装で、saveAsというメソッド名が短く衝突しやすいので変更される可能性が高い)
var fileSaver = window.saveAs(blob, "tempfile.txt");
createObjectURL(以前はcreateBlobURLという名前)でBlobをURLに変換することができ、そのURLをimg要素のsrcなどに設定することができます。
img.src = webkitURL.createObjectURL(blob);
Chromeの9以降のバージョンで、起動オプションに
--unlimited-quota-for-files --allow-file-access-from-files
をつけることで実際に試すことができます。
もうすぐChrome拡張・Chrome Web AppsでFileSystem APIを活用できるようになります。