JavaScriptでローカルファイルを自在に操る - File API

2013年2月6日(水)
山田 祥寛(YAMADA, Yoshihiro)

TIPS 056:バイナリファイルを読み込む(2)

FileReaderオブジェクトには、もうひとつバイナリファイルを読み込むための
readAsBinaryStringメソッドが用意されています。
例えば以下は、TIPS 055のサンプルをreadAsBinaryStringメソッドで書き換えたものです。

[リスト04]画像ファイルの内容を表示(readBinary.html)

01<script>
02window.addEventListener('DOMContentLoaded', function() {
03  // ファイルが指定されたタイミングで、その内容を表示
04  document.querySelector("#file").addEventListener('change', function(e) {
05    // File APIを利用できるかをチェック
06    if (window.File) {
07      // 指定されたファイルを取得
08      var input = document.querySelector('#file').files[0];
09      // ファイル読み込みの準備
10      var reader = new FileReader();
11      // ファイルの読み込みに成功したら、その内容を<img id="result">に反映(2)
12      reader.addEventListener("load", function(event){
13        // バイナリデータを取得
14        var raw = reader.result;
15        // バイト配列を格納する変数
16        var bytes = [];
17        // バイナリデータを順に取得(0xffとの論理積でバイト値に変換(1))
18        for (var i = 0; i < raw.length; i++){
19          bytes[i] = raw.charCodeAt(i) & 0xff;
20        }
21        // Base64エンコードしたものをData URL形式に整形(2)
22        document.querySelector('#result').src = "data:" + input.type
23          + ";base64," + btoa(String.fromCharCode.apply(String, bytes));
24      } , true);
25      reader.readAsBinaryString(input);
26    }
27  }, true);
28});
29</script>

readAsBinaryStringメソッドは、生のバイナリデータを取得しますので、サンプルではこれをバイト配列に変換した上で(1)、更にこれを文字列変換し、最終的に、btoaメソッドでBase64エンコードしています(2)。これは、バイナリデータからバイト文字列を得る定型的な流れです。Base64エンコードできてしまえば、あとは「data:[コンテンツタイプ][;base64],データ本体」の構文に従って、Data URLを組み立てるだけです。

サンプルを見てもわかるように、取得したデータをそのまま

TIPS 057:ファイル読み込みに失敗した場合の処理を定義する

FileReaderオブジェクトにerrorイベントリスナーを登録しておくことで、ファイルの読み込みに失敗した場合に、エラーメッセージの表示などのエラー処理を行えます。

[リスト05]読み込みエラー時にエラーメッセージを表示(readError.html)

01<script>
02window.addEventListener('DOMContentLoaded', function() {
03  // ファイルが指定されたタイミングで、その内容を表示
04  document.querySelector("#file").addEventListener('change', function(e) {
05    // File APIを利用できるかをチェック
06    if (window.File) {
07      // 指定されたファイルを取得
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;
13      }, true);
14      // 読み込みエラー時の処理
15      reader.addEventListener('error', function(e) {
16        // エラーコードに対応するメッセージを準備(1)
17        var errors = [
18          '',
19          '指定のファイルが見つかりません。',
20          '読み込み権限がありません。',
21          '処理が中断されました。',
22          '読み込み中にエラーが発生しました。',
23          'ファイルサイズが大きすぎます。'
24        ];
25        // エラーコードに応じてメッセージを表示(2)
26        document.querySelector('#err').innerHTML = errors[reader.error.code];
27      }, true);
28    }
29  }, true);
30});
31</script>

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)

01<!DOCTYPE html>
02<html>
03<head>
04<meta charset="UTF-8" />
05<title>HTML5 TIPS</title>
06<script>
07window.addEventListener('DOMContentLoaded', function() {
08    // ファイルが指定されたタイミングで、その内容を表示
09    document.querySelector("#file").addEventListener('change', function(e) {
10      // 指定されたファイルを取得
11      if (window.File) {
12      // 指定されたファイルを取得
13      var input = document.querySelector('#file').files[0];
14      // ファイル読み込みの準備
15      var reader = new FileReader();
16      // ファイルの読み込みに成功したら、その内容を<img id="result">に反映
17      reader.addEventListener('load', function(e) {
18        document.querySelector('#result').src = reader.result;
19      }, true);
20     
21      // ファイルの読み込み中に進捗状況を表示
22      reader.addEventListener('progress', function(e) {
23        // 「ロード済みサイズ÷総サイズ」で読み込み率を求める
24        document.querySelector('#prog').innerHTML =
25          Math.floor(e.loaded /e.total * 100);
26      }, true);
27 
28      // ファイルの内容をData URL形式で取得
29      reader.readAsDataURL(input);
30    }
31  }, true);
32});
33</script>
34</head>
35<body>
36ファイル:
37<input id="file" name="file" type="file" />
38<hr />
39<span id="prog" style="color:Blue;">0</span>%読み込み済み
40<img id="result" />
41</body>
42</html>
図4:ファイル読み込みの進捗をパーセント表示

progressイベントリスナーの中では、totalプロパティでファイルの総サイズを、loadedプロパティで読み込み済みのサイズを、それぞれ取得できます。そこでサンプルでは、「loaded ÷ totaled × 100」という式で、読み込み済みのサイズ割合を求めています。progressイベントは、ファイルの読み込み中に連続して発生しますので、サンプルのようなリスナーを設けておくことで、読み込み割合が徐々に増えていく効果を実装しています。

  • JavaScriptでローカルファイルを自在に操る - File API

著者
山田 祥寛(YAMADA, Yoshihiro)
WINGSプロジェクト

有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表:山田祥寛)。おもな活動は、Web開発分野の書籍/雑誌/Web記事の執筆。ほかに海外記事の翻訳、講演なども幅広く手がける。2011年3月時点での登録メンバは36名で、現在もプロジェクトメンバーを募集中。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています