それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

html5のW3C FileAPIについて、調べてまとめた。

html5のファイルAPIについて調べた。http://www.w3.org/TR/FileAPI/ を読みながら、メモ。やっぱり本家ドキュメントは頼りになるのね。

FileAPIはなにか

  • ローカルファイルにアクセスできる。
  • アクセスできるローカルファイルはinput で指定された物だけ。*1

使い方

input に files タイプを指定するとFileAPIの対象になる。

<input type=files  >

filesタイプの読み込み方

file = document.forms[0].elements[0].files[0]

このように、<input type=files/>へJS経由でアクセスできる。


input type=filesの項目は、複数ファイルの配列になっている。FileListオブジェクト呼ぶ

FileList オブジェクト

通常の配列みたいなオブジェクトして定義されている。つまり配列だと思っておけば良い。

files = document.forms[0].elements[0].files
file.length
files[0]
files.item(0)

File。FileListの中に入ってるオブジェクト

input type=filesでユーザーが指定したファイルのオブジェクトが入っている。
File/FileListは、Iteratorパターンの関係にあるの

Fileオブジェクトでとれる物。

  • ファイル名
  • サイズ
  • 最終更新日
files = document.forms[0].elements[0].files
file = files[0]
file.name                  // => "test.xls"
files.lastmodifideDate // => ""
files.size                  //  => 1234567

ただし、内容読み込みは出来ない。

なぜか?

 input type=fileで、ブラウザがファイルを読み込んでたら遅いジャン

だったらどうするの?

 ローカルファイルすら非同期で読み込みます。

つまり?

ローカルは http:// https://のような file:// のScheme空間だと認知しておけば良い。

File.read メソッドって無いけど?

ないよ。

Fileは FileReader()をつかって非同期に読みこみます。 File は file://のURLを示すオブジェクトなんだ。

非同期で読み込むって?

XHRみたいに読み込めば良いんだよ。

new XmlHttp()のかわりに、new FileReader()する

何度も言うけど、非同期だからね!!

reader = new FileReader()
file = document.forms[0].elements[0].files[0]
reader.readAsText(file, 'UTF-8')#このあとはEvent処理に任せるよ!
非同期なんだから、Event処理を書いとかないとしょうが無い。
reader = new FileReader()
reader.onload     = function(evt){} //読み込み完了したら呼ばれる。
reader.onprogress = function(evt){} //ファイル読み込み中に呼ばれる。
reader.onerror    = function(ev){}  //エラー時に呼ばれる。
reader.readAsText(file, 'UTF-8')#Event処理に任せるよ!

イベントにはどんな種類があるの?

Filereaderが持ってるイベントはこんなのがある

ハンドラ名 イベント タイミング
onloadstart loadstart データ読み込み開始時点
onprogress progress データを読み込んだタイミングで
onabort abort 強制停止(abort()関数)で止めた時点
onerror error リクエストがエラーだった(404とか)
onload load リクエスト成功時
onloadend loadend リクエスト完了時(エラーでも成功でも関係なく、送信が完了した時点で呼ばれる)


イベントは以上です。

ぐだぐだ言わずに、ファイル読めりゃ良いんだよ

僕らはファイルを読み込みたいだけなんだ。

reader = new FileReader()
file = document.forms[0].elements[0].files[0]
reader.readAsText(file, 'UTF-8')#このあとはEvent処理に任せるよ!

///しばらく待つ。
reader.readyState //これが2になれば読み込みおわり


while(reader.readyState!=2){  }
//ファイルの中身を見る

reader.result   

readyStateとか見覚えあるよね



そうXHRみたいなもんなんだよ。


つまり

比較してみよう

データ オブジェクト
Ajax URL:アドレス  Xmlhttp
FileAPI Fileオブジェクト FileReader


対で覚えるとイメージしやすいみたい。


何で非同期になってるのよ。


ファイル読み込み程度で、ほかのJSの動作をストップさせるともったいない。だからマルチスレッドで動くようにファイル読み込みを別スレッドにしてる。HTMLを読み込んでDOMを構築するときにIMGやCSSを非同期に読み込むでしょ?あれと同じことをローカルファイルでもやってる。

ってことみたい


シンプルに、覚えよう。

次の原理として覚えることにした。

ローカルファイルはfile://スキーマ。http://スキーマと同じ扱いを受ける

絶対に同期できないの?

もちろん出来る。

XMLHTTPに同期通信が用意されているように、ファイルにも同期が用意されている。それが FileReaderSync


全部非同期で良いジャン?

いや、WebWorkersでプログラマがスレッド作れるから、スレッド同期処理はあった方が良い。

部分的にファイル読込できないの?

HTTPはファイルの部分取得が出来る、FileAPIは出来ないの?
もちろん出来る。File#sliceがそれ。

まとめ

HTTPとおなじ扱いのFILEとして定義されている。

同期・非同期、部分読み込みがあるのです。やっぱHTTPと同じだよね。Fileだからといっても、思想は何も変わらない。オブジェクトが変わるだけ。




ところで、読み込んだファイルをどう使うの?

画像をインラインに埋め込む記述を覚えていますか?

     <img src="data:123456yjgbvd”/>


ファイルAPIで読み込んだファイル内容は、

     <img src=“blob:123456yjgbvd”/>

と書き込み、使うことが出来る。

data: だと base64エンコードが必要だからめんどくさいけど、blogならバイナリそのままで楽ちん。


これをblob: プロトコルと呼びます。


講釈は良いから、使い方を

説明多くてすいません。こうやります。

var file = document.getElementById('file').files[0];
     if(file){
       blobURLref = window.URL.createObjectURL(file);
       myimg.src = blobURLref; 
}

1:window.URL.createObjectURL() にファイルを渡すと blob:xxxxxのURLが帰ってきます。
2:blob:のURLをimg.srcに埋め込めば終わり。

簡単ですね。

追記:window.URLについて 2012-08-06

chrome/safariWebkitでは、window.URLがベンダープレフィックス付きでないとアクセス出来ない場合もあります。

window.webkitURL

などとベンダープレフィックス webkitをつけてくださいな。

追記 blob URL生成はもっと簡単な方法がありました。

var file = document.getElementById('file').files[0];
var reader = new FileReader();
reader.readAsDataURL(file)
//暫く待つ
while(reader.readyState!=2){  }

img.src = reader.result  ;

追記の追記。Android4.0では readAsDataURLがうまく動作しなかった。window.URL.createObjectURL(file)を使うのが無難

追記 BLOBについて:2012/08/06

意図的にBlobを外してたけど、やっぱり書いた方がいいとおもうので追記

FileAPIは file://みたいなもんだと言いました。ネットの先にあるのがhttp、ローカルファイルにあるのがfile、ではHTML中たとえばCanvasなどに入ってるデータは何になるのか?それがblobです。 canvsなどのメモリに載ってるデータはBLOBです。読み込んだデータもHTML中のimgタグなどに存在するのでBlobです。

プロトコル 書式
HTTP(s) http://
File file://
Blob blob://

みたいなもんです。

blobは、読み込んだデータそのものを表す。

Fileは Blobの拡張で定義されてる、なぜか?ファイルを読み込んだら、バイナリが出てくるからに他かならない。

出てきたバイナリはそのままCanvasに入れるなり、Imageにいれるなり、Videoで再生するなどになる。


参考資料

http://www.w3.org/TR/FileAPI/

W3Cだけでかなりおなかいっぱいになれる。

*1:イベントからも取れるけど、まずはinput から抑えるといいよ