2011年12月6日

HTML5 の File API を使ってみる

CSV を読み込んで JSON で出力できるようにします。 CSV の仕様は意外と難しいので、単純にカンマで区切られているテキストファイルだけを想定します。

File API の仕様などはこちら。 基本的にこれらのサンプルスクリプトをまとめたものが、上記のデモになります。

なお、イベント管理には jQuery を使います。

form を作る

まずは <form> 要素を作成します。 複数のファイルを選択できるよう、 multiple を有効にします。

        <form>
        Select CSV files: <input type="file" id="files" name="files[]" multiple="multiple" />
        </form>

この要素に change イベントを割り当てます。 コールバックに渡されるイベントオブジェクトの target には files があり、 これは FILE オブジェクトの配列になっています。 イベント自体と FILE の扱いは分離したいので、別に定義する関数に処理を投げます。

                $(selector).bind("change", function(e) {
                    var files = e.target.files;
                    handleFiles(files);
                });

ファイルを処理する

先ほどの handleFiles は簡単にループを回すとして、個別のファイルは次のように処理してみます。

  • メタ情報を表示する
  • CSV ファイルの場合は読み込み処理を実行する

スクリプトにまとめると次のような感じ。 関数の戻り値が真の場合のみ読み込み処理を継続します。

        function parseFile(f) {
            var dt = [];
            dt.push({Name: f.name,
                     Type: f.type || 'n/a',
                     Size: f.size,
                     LastModified: f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a'});
            $("#file-list-template").tmpl(dt).appendTo('#file-list');
            return f.type && f.type.match("text/csv");
        }

ファイルの読み込みは次のようになります。 コールバックを設定してから、読み込む文字列を与えます。 opts という変数に適当なコールバックが設定されている場合には、 適切なタイミングでそのコールバックが呼ばれるでしょう。

        function readFile(readFile) {
            var reader = new FileReader();
            // Handle progress, success, and errors
            reader.onprogress = opts.progress || function(e) {};
            reader.onerror = opts.error || function(e) {};
            reader.onload = opts.load || function(e) {};
            reader.readAsText(readFile, "UTF-8");
        }

readAsText で読み込んだ場合はイベントオブジェクトの target を通じて、 普通の文字列を取得できます。 後は自由にその文字列を処理すれば良いだけです。

                var fileString = evt.target.result,

ドラッグに対応する

ついでにドラッグ&ドロップにも対応させます。

まずは適当な HTML 要素を準備します。

        <div id="drop-zone">Drop CSV files here</div>

そこにイベントハンドラを割り当てますが、ここのイベント処理がちょっと曲者です。

  • stopPropagation() を呼んでブラウザにネイティヴの挙動をさせない。
  • jQuery のイベントに未登録のものは originalEvent を参照する必要がある。

詳しくはこちらのスライドで説明されています。

スクリプトにまとめると次のような感じ。 originalEvent を介さないと、 dataTransfer が見つからない、という理由でエラーになります。 (jQuery のバージョンによって異なるので、新しいバージョンだけを使う場合は気にしなくて良いかも)

                    .bind("drop", function(e) {
                        e.stopPropagation();
                        e.preventDefault();
                        var files = e.originalEvent.dataTransfer.files;
                        handleFiles(files);
                    });

終わりに

HTML5 の File API を使って、CSV ファイルの中身を JSON で出力してみました。 CSV と言っても非常に簡易なものしか扱えませんが、取っ掛かりとしては十分かな、と思います。

File API はテキストデータだけでなくバイナリデータも扱えますので、 様々なリーダーを試してみるとおもしろそうです。

コメントを投稿