File APIでローカルファイルを読み込む

最近のWebブラウザには、File APIという「ユーザーが指定したローカルファイルをJavaScriptで読み込む」APIが実装されています。このFile APIの導入でセキュリティ面から制約されていたJavaScript側からのローカルファイルへのアクセスが、限定(ユーザーによる操作が必須)的な状況とはいえ可能になったわけですね。

File APIを使えば、JavaScriptで直接ローカルファイルのデータを処理して結果をユーザーに提示することができるので、サーバーとの通信を減らしたりWebブラウザ上のJavaScriptのみで完結するWebアプリケーションの可能性も広がることになるでしょう。

ユーザーがFile APIで使用するローカルファイルを指定するには、「fileタイプのinputタグで指定する」「ドラッグ&ドロップでWebブラウザ内のHTML要素にファイルを渡す」方法があります。とりあえず、今回はinputタグで指定したローカルファイルを読み込んでみることにしましょう。

inputタグで指定されたローカルファイルにアクセスするためには、inputタグのfilesプロパティに格納されているファイルオブジェクトを使います。File APIが実装されているWebブラウザでは、typeとしてfileが指定されているinputタグのプロパティにfilesというファイルオブジェクトの配列があって、この配列に指定されているファイルの情報が格納されています。

配列になっているのは、inputタグの設定で複数のファイルを指定することができるからですが、とりあえず今回は指定できるファイルは一つのみ(デフォルト状態)という状態を前提にしましょう。その場合は、指定されたファイルがfiles[0]に格納されているのでそれを見ればよいことになります。

まずは、ファイルオブジェクトのプロパティで指定されたファイルの名前、それにタイプ(データ形式)とファイルサイズを調べてみましょうか。

inputでファイルを指定すると、onchangeイベントが発生するので、そのイベントハンドラ内でファイル情報を取得し、表示してみることにします。

<form>
	<input type="file" id="file_api_input1" onchange="onFileInput1()">
</form>

<script>

function onFileInput1() {

	var item = document.getElementById('file_api_input1').files[0];

	alert("name:" + item.name + " type:" + item.type + " size:" + item.size);

}

</script>

次に、File APIでJavaScriptからローカルファイルを読み込んでみます。

ファイルの読み込みには、FileReaderオブジェクトを使います。FileReaderを作成し、読み込みメソッドの引数にファイルオブジェクトを渡して読み込む形式です。

FileReaderのファイル読み込みメソッドには、テキストとして読み込むreadAsText()、バイナリデータとして読み込むreadAsBinaryString()/readAsArrayBuffer()、バイナリデータをDataURI形式の文字列に変換して取得できるreadAsDataURL()が用意されています。

FileReaderの読み込みメソッドは、いずれも非同期で直ち(実際にローカルファイルの読み込みが完了する前)に制御を返す点に注意が必要です。読み込んだデータを利用するには、読み込みメソッドを呼び出す前に読み込みが完了したときに起こるonloadイベントに対するイベントハンドラを設定し、onloadイベントハンドラ内でデータに対する処理を行う必要があります。

今回は、DataURLとして取得するreadAsDataURL()を使ってみましょう。
DataURLは、バイナリデータをURL形式の文字列に変換し、HTMLファイルなどに直接埋め込むためのデータ形式です。画像ファイルを別に用意しなくてもimgタグのsrc属性にDataURL形式の画像データを直接指定できたり、aタグのhref属性に指定するとリンクをクリックしてそのデータをWebブラウザ(やアプリケーション)で開くことができます。

ファイルの内容をDataURLとして取得し、予め用意しておいたaタグのhrefにその文字列を指定してやれば「指定されたローカルファイルの内容を表示するリンク」ができるわけですね。

以下のファイル選択欄で小さな(数KB程度の)画像やテキストを指定してみてください。

ファイル情報: ファイル内容:

<form>
	<input type="file" id="file_api_input2" onchange="onFileInput2()">
</form>
<p>ファイル情報:<span id="input_file_info"></span> ファイル内容:<span id="input_file_link"></span></p>

<script>

function onFileInput2() {

	var item = document.getElementById('file_api_input2').files[0];

	var info = "name:" + item.name + " type:" + item.type + " size:" + item.size;

	document.getElementById('input_file_info').innerHTML = info;

	var fr = new FileReader();

	fr.onload = onFileLoad;

	fr.readAsDataURL(item);

}

function onFileLoad(e) {

	var elm = document.getElementById("input_file_link");

	elm.innerHTML = '<a href="' + e.target.result + '">表示</a>';

}

</script>

実際に読み込んだDataURLの文字列を確認したいときは、リンクを右クリックしてURLをコピーし、テキストエディタに貼り付けてみてください。

File APIを使ってJavaScriptでローカルファイルの処理が可能になれば、「画像ファイルを読み込んで画像処理を行いlocalStorageに結果を保存して後日呼び出したりDataURLを介してローカルファイルとして保存する」ような(サーバーなしで完結する)Webアプリケーションも可能になるでしょう。Webブラウザ(HTML5とJavaScript)が、また一歩「アプリケーション実行のためのプラットフォーム」に近づきそうです。


創作プログラミングの街