HTML5では、新たに追加されたFile APIを利用することで、ローカルのファイルやファイルシステムをJavaScriptのコードから操作できるようになりました。File APIを利用することで、(例えば)ローカルのファイルを読み込み、Ajax経由でサーバサイドに引き渡すような操作も、ごくシンプルなコードで実装できます。
[第7回目次]
- TIPS 053:ファイルの名前/種類/サイズを取得する
- TIPS 054:テキストファイルを読み込む
- TIPS 055:バイナリファイルを読み込む
- TIPS 056:バイナリファイルを読み込む(2)
- TIPS 057:ファイル読み込みに失敗した場合の処理を定義する
- TIPS 058:ファイル読み込み時の進捗状況を表示する
File APIは、大きく以下の仕様に分類できます。
表1:File APIの種類
種類 |
機能 |
File API |
ファイル情報やデータ本体の読み込み |
File API:Writer |
ファイルへの書き込み |
File API:Directories and System |
仮想的なファイルシステムの操作 |
サンプル一式は、会員限定特典としてダウンロードできます。記事末尾をご確認ください。
ただし、File API:Writer/File API:Directories and Systemは、執筆時点では対応ブラウザも限られていることから、本稿でもFile APIを中心に解説を進めます。File APIの対応状況は、以下のとおりです。
表2:File APIの対応バージョン
ブラウザ |
対応バージョン |
Internet Explorer |
10以降 |
Firefox |
3.5以降 |
Google Chrome |
6以降 |
Safari |
5以降 |
Opera |
10以降 |
※ただし、SafariではFileReaderオブジェクトを、Internet Explorer 10ではreadAsBinaryStringメソッドをサポートしていません。
TIPS 053:ファイルの名前/種類/サイズを取得する
Fileオブジェクトを利用することで、ローカルファイルの情報にアクセスできます。
例えば以下は、<input type="file">要素で指定されたファイルの名前やサイズなどを表示するサンプルです。
[リスト01]ファイルの情報を取得するコード(fileinfo.html)
04 | <meta charset="UTF-8" /> |
05 | <title>HTML5 TIPS</title> |
10 | <meta charset="UTF-8" /> |
11 | <title>HTML5 TIPS</title> |
13 | window.addEventListener('DOMContentLoaded', function() { |
14 | // ファイルが指定されたタイミングで、その情報を表示 |
15 | document.querySelector("#file").addEventListener('change', function(e) { |
16 | // File APIを利用できるかをチェック(1) |
19 | var input = document.querySelector('#file').files[0]; |
21 | document.querySelector('#name').innerHTML = input.name; |
22 | document.querySelector('#type').innerHTML = input.type; |
23 | document.querySelector('#size').innerHTML = input.size / 1024; |
24 | document.querySelector('#urn').innerHTML = input.urn; |
32 | <input id="file" name="file" type="file" /> |
34 | <li>名前:<span id="name"></span></li> |
35 | <li>種類:<span id="type"></span></li> |
36 | <li>サイズ:<span id="size"></span></li> |
37 | <li>URN:<span id="urn"></span></li> |
図1:指定されたファイルの名前/サイズなどを表示
File APIは新しい機能なので、利用する前にまず、ブラウザが対応しているかをチェックしなければなりません。これを行っているのが(1)です。
Fileプロパティはファイル情報にアクセスするためのプロパティで、Fileオブジェクトを取得します。(1)ではFileプロパティにアクセスしてみて、アクセスできればFile APIに対応していると判断し、以降の処理を行っているわけです(これまでに何度も登場した「機能テスト」です)。
Fileオブジェクトは、<input type="file">要素(ファイル入力ボックス)から選択されたファイル、または、ドラッグ&ドロップされたファイルから取得できます。今回扱っているのは前者です(後者の方法については、次回改めて扱います)。
ファイル入力ボックスで選択されたファイルを取得するには、filesプロパティにアクセスしてください(2)。filesプロパティは指定されたファイル(群)をFileオブジェクト配列として返します。ここではfiles[0]として、無条件に先頭のファイル(Fileオブジェクト)を取得します。
Fileオブジェクトを取得できてしまえば、あとは必要な情報を取り出すだけです(3)。以下に、Fileオブジェクトでアクセスできる主なプロパティをまとめておきます。
表3:Fileオブジェクトの主なプロパティ
プロパティ |
概要 |
name |
名前 |
type |
コンテンツタイプ |
size |
サイズ(バイト単位) |
urn |
URN(リソース識別子) |
なお、サンプルでは単一のファイルを扱う方法について触れましたが、以下のようにすることで、複数のファイルを取得することもできます。
1 | var inputs = document.querySelector('#file').files; |
3 | for (var i = 0; i < inputs.length; i++) { |
8 | <!--multiple属性で、複数ファイルの選択を許可--> |
9 | <input id="file" name="file" type="file" multiple /> |
TIPS 054:テキストファイルを読み込む
File APIでは、ファイルのメタ情報を取得するばかりではありません。ファイルの内容を読み込み、JavaScriptのコードの中で利用することもできます。
例えば以下は、<input type="file">要素で指定されたテキストファイルを読み込み、ページ上に表示する例です。
[リスト02]テキストファイルの内容を表示(readText.html)
04 | <meta charset="UTF-8" /> |
05 | <title>HTML5 TIPS</title> |
07 | window.addEventListener('DOMContentLoaded', function() { |
08 | // ファイルが指定されたタイミングで、その内容を表示 |
09 | document.querySelector("#file").addEventListener('change', function(e) { |
10 | // File APIを利用できるかをチェック |
13 | var input = document.querySelector('#file').files[0]; |
15 | var reader = new FileReader(); |
16 | // ファイルの読み込みに成功したら、その内容を<div id="result">に反映(2) |
17 | reader.addEventListener('load', function(e) { |
18 | var output = reader.result.replace(/(\n|\r)/g, '<br />'); |
19 | document.querySelector("#result").innerHTML = output; |
21 | // ファイルの内容をテキストとして取得(3) |
22 | reader.readAsText(input, 'UTF-8'); |
30 | <input id="file" name="file" type="file" /> |
32 | <!--読み込み結果を反映する場所を用意--> |
33 | <div id="result"></div> |
図2:テキストファイルの内容を表示
ファイルを読み込むには、FileReaderというオブジェクトを利用します(1)。(2)ではファイルのロードが完了したloadイベントのタイミングで、ファイルの内容を取り出し、テキストを
要素にセットするよう、イベントリスナーを定義しています。ファイルの内容には、FileReaderオブジェクトのresultプロパティでアクセスしてください。ここでは、ブラウザに正しく改行を反映させるために、replaceメソッドで改行文字(\n、\r)を
要素に置き換えている点にも注目です。
ただし、(2)の段階ではイベントリスナーを定義しているだけで、まだファイルの読み込みそのものが実施されているわけではありません。ファイルの読み込みを実行しているのは、(3)のreadAsTextメソッドです。readAsTextメソッドは、引数に「読み込みファイル(Fileオブジェクト)」「文字コード」の順で指定します。文字コードがUTF-8の場合には、第2引数は省略しても構いません。
TIPS 055:バイナリファイルを読み込む
FileReaderオブジェクトを利用することで、テキストファイルとほぼ同じ要領で画像/音声などのバイナリファイルを読み込むこともできます。
例えば以下は、<input type="file">要素で指定された画像ファイルを読み込み、
要素に反映する例です。
[リスト03]画像ファイルの内容を表示(readDataURL.html)
04 | <meta charset="UTF-8" /> |
05 | <title>HTML5 TIPS</title> |
07 | window.addEventListener('DOMContentLoaded', function() { |
08 | // ファイルが指定されたタイミングで、その内容を表示 |
09 | document.querySelector("#file").addEventListener('change', function(e) { |
10 | // File APIを利用できるかをチェック |
13 | var input = document.querySelector('#file').files[0]; |
15 | var reader = new FileReader(); |
16 | // ファイルの読み込みに成功したら、その内容を<img id="result">に反映 |
17 | reader.addEventListener('load', function(e) { |
18 | document.querySelector("#result").src = reader.result; |
20 | // ファイルの内容をData URL形式で取得(1) |
21 | reader.readAsDataURL(input); |
29 | <input id="file" name="file" type="file" /> |
31 | <!--読み込み結果を反映する場所を用意--> |
図3:画像ファイルの内容を表示
画像ファイルを読み込むには、readAsTextメソッドの代わりにreadAsDataURLメソッドを利用します(1)。これによって、画像ファイルをData URL形式で取得できます。
Data URLとは、URLに直接データを埋め込むための表現で、以下のような形式で表せます。
data:[コンテンツタイプ][;base64],データ本体
Data URLを利用することで、画像や音声などのデータをいちいちファイルに落とし込むことなく、例えば以下のように
要素や要素に直接埋め込めるようになります。

(2)のloadイベントリスナーでは、読み込んだ画像データ(reader.result)を、そのまま
要素のsrc属性にセットしています。
TIPS 056:バイナリファイルを読み込む(2)
FileReaderオブジェクトには、もうひとつバイナリファイルを読み込むための
readAsBinaryStringメソッドが用意されています。
例えば以下は、TIPS 055のサンプルをreadAsBinaryStringメソッドで書き換えたものです。
[リスト04]画像ファイルの内容を表示(readBinary.html)
02 | window.addEventListener('DOMContentLoaded', function() { |
03 | // ファイルが指定されたタイミングで、その内容を表示 |
04 | document.querySelector("#file").addEventListener('change', function(e) { |
05 | // File APIを利用できるかをチェック |
08 | var input = document.querySelector('#file').files[0]; |
10 | var reader = new FileReader(); |
11 | // ファイルの読み込みに成功したら、その内容を<img id="result">に反映(2) |
12 | reader.addEventListener("load", function(event){ |
14 | var raw = reader.result; |
17 | // バイナリデータを順に取得(0xffとの論理積でバイト値に変換(1)) |
18 | for (var i = 0; i < raw.length; i++){ |
19 | bytes[i] = raw.charCodeAt(i) & 0xff; |
21 | // Base64エンコードしたものをData URL形式に整形(2) |
22 | document.querySelector('#result').src = "data:" + input.type |
23 | + ";base64," + btoa(String.fromCharCode.apply(String, bytes)); |
25 | reader.readAsBinaryString(input); |
readAsBinaryStringメソッドは、生のバイナリデータを取得しますので、サンプルではこれをバイト配列に変換した上で(1)、更にこれを文字列変換し、最終的に、btoaメソッドでBase64エンコードしています(2)。これは、バイナリデータからバイト文字列を得る定型的な流れです。Base64エンコードできてしまえば、あとは「data:[コンテンツタイプ][;base64],データ本体」の構文に従って、Data URLを組み立てるだけです。
サンプルを見てもわかるように、取得したデータをそのまま
、
TIPS 057:ファイル読み込みに失敗した場合の処理を定義する
FileReaderオブジェクトにerrorイベントリスナーを登録しておくことで、ファイルの読み込みに失敗した場合に、エラーメッセージの表示などのエラー処理を行えます。
[リスト05]読み込みエラー時にエラーメッセージを表示(readError.html)
02 | window.addEventListener('DOMContentLoaded', function() { |
03 | // ファイルが指定されたタイミングで、その内容を表示 |
04 | document.querySelector("#file").addEventListener('change', function(e) { |
05 | // File APIを利用できるかをチェック |
08 | var input = document.querySelector('#file').files[0]; |
09 | var reader = new FileReader(); |
10 | reader.readAsDataURL(input); |
11 | reader.addEventListener('load', function(e) { |
12 | document.querySelector('#result').src = reader.result; |
15 | reader.addEventListener('error', function(e) { |
16 | // エラーコードに対応するメッセージを準備(1) |
25 | // エラーコードに応じてメッセージを表示(2) |
26 | document.querySelector('#err').innerHTML = errors[reader.error.code]; |
errorイベントリスナーの中では、error.codeプロパティでエラーコードにアクセスできます。エラーコードの意味は、以下のとおりです。
表4:error.codeプロパティの値
エラーコード |
概要 |
1 |
指定のファイルが存在しない |
2 |
権限エラー(読み取り権限を持たないなど) |
3 |
ファイルの読み込みを中断された |
4 |
読み込み中のエラー |
5 |
ファイルサイズが許容上限を超えた |
サンプルでは、エラーコード1~5に対応するエラーメッセージを配列errorsにセットしておくことで(1)、codeプロパティの値に応じてメッセージを返しているわけです(2)。例えばエラーコード1で、erros[1]が取り出されます。
TIPS 058:ファイル読み込み時の進捗状況を表示する
読み込みの状況を追跡するには、progressイベントを利用します。progressイベントは、ファイル読み込みの開始から終了までの間、連続して発生するイベントです。
以下では、このprogressイベントを利用して、ファイルの読み込み状況を「●○%読み込み済み」のように、テキストで表示します。
[サンプル]読み込み率をテキスト表示するコード(readProgress.html)
04 | <meta charset="UTF-8" /> |
05 | <title>HTML5 TIPS</title> |
07 | window.addEventListener('DOMContentLoaded', function() { |
08 | // ファイルが指定されたタイミングで、その内容を表示 |
09 | document.querySelector("#file").addEventListener('change', function(e) { |
13 | var input = document.querySelector('#file').files[0]; |
15 | var reader = new FileReader(); |
16 | // ファイルの読み込みに成功したら、その内容を<img id="result">に反映 |
17 | reader.addEventListener('load', function(e) { |
18 | document.querySelector('#result').src = reader.result; |
22 | reader.addEventListener('progress', function(e) { |
23 | // 「ロード済みサイズ÷総サイズ」で読み込み率を求める |
24 | document.querySelector('#prog').innerHTML = |
25 | Math.floor(e.loaded /e.total * 100); |
28 | // ファイルの内容をData URL形式で取得 |
29 | reader.readAsDataURL(input); |
37 | <input id="file" name="file" type="file" /> |
39 | <span id="prog" style="color:Blue;">0</span>%読み込み済み |
図4:ファイル読み込みの進捗をパーセント表示
progressイベントリスナーの中では、totalプロパティでファイルの総サイズを、loadedプロパティで読み込み済みのサイズを、それぞれ取得できます。そこでサンプルでは、「loaded ÷ totaled × 100」という式で、読み込み済みのサイズ割合を求めています。progressイベントは、ファイルの読み込み中に連続して発生しますので、サンプルのようなリスナーを設けておくことで、読み込み割合が徐々に増えていく効果を実装しています。