[HTML5] FileSystem APIの概要と活用 #1

2013.11.27

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

FileSystem API

FileSystem APIとはWebアプリケーションでユーザのローカルにデータの保存、読込ができるAPIです。
ただし残念なことに対応してるブラウザが多くはありません。
今回はChrome※1を使っていますが、Chomeもブラウザのバージョンが上がるごとに仕様が少しずつ変わっていたりしています。APIのメソッドにもベンダプレフィックスがついていることからまだ実験的な段階といえます。
それでも可能性が色々あるAPIですので、今回取り上げてみました。

※1 chromeのはバージョン31を使用しています。

保存方法について

FileSystem APIには「TEMPORARY」「PERSISTENT」の形式が2種類があります。
TEMPORARYで保存したファイルは空き容量が必要になった時などブラウザの判断でファイルを削除することができるので一時的に保存することを想定しています。ただ一時的とはいえ、ブラウザを閉じたとしてもファイルは削除されることはありませんので安心して下さい。
PERSISTENTはユーザまたはアプリケーションの許可なしには削除されることはありません。ただし、ファイルを保存するのにユーザからの許可が必要になります。こちらについては後でまた説明したいと思います。

TEMPORARY形式の読込

ではまず「TEMPORARY」形式のファイル読込のサンプルを見てみましょう。以下のサンプルはtmp.txtを読込み、読込んだデータをid=txtの要素に値を設定しています。onloadInitはbodyから呼び出しています。

function onloadInit() {
    navigator.webkitTemporaryStorage.requestQuota(1024*1024*5, function(bytes) {       
        // TEMPORARY形式を指定する
        window.webkitRequestFileSystem(window.TEMPORARY, bytes, function(fs) {
           // ファイル取得
           fs.root.getFile('tmp.txt', {create: true}, function(fileEntry ) {
                fileEntry.file(
                    function(file) {
                        var reader = new FileReader();
                        reader.onloadend = function(e) {
                            data = e.target.result;
                            // 読込んだ値を設定する
                            document.getElementById('txt').value = data;
                        };
                        reader.readAsText(file);
                    });
                });
            });
        }
    );
}
<body onload="onloadInit()">
</body>

まず、最初にユーザに対して「1024*1024*5」バイトのファイルを使用することを要求しています。

navigator.webkitTemporaryStorage.requestQuota(1024*1024*5, function(bytes) ) {

ファイル名を指定して読込んでいる部分が以下になりますがここでは「create:true」と指定しています。これはファイルが無ければ新規でファイルを作成する設定になります。

fs.root.getFile('tmp.txt', {create: true}, function(fileEntry) {

PERSISTENT形式の読込

次に「PERSISTENT」形式でのファイル読込のサンプルを見てみましょう。

 function onloadInit() {
    navigator.webkitPersistentStorage.requestQuota(1024*1024*5, function(bytes) {
         window.webkitRequestFileSystem(window.PERSISTENT, bytes, function(fs) {
           // ファイル取得
           fs.root.getFile('tmp.txt', {create: true}, function(fileEntry) {
                 fileEntry.file(
                    function(file) {
                        var reader = new FileReader();
                        reader.onloadend = function(e) {
                            data = e.target.result;
                            // 読込んだ値を設定する
                            document.getElementById('txt').value = data;
                        };
                        reader.readAsText(file);
                    });
                });
            });
        }
    );
}

違いは以下の2箇所になります。(navigator.webkitPersistentStorageとwindow.PERSISTENT)

     navigator.webkitPersistentStorage.requestQuota(1024*1024*5, function(bytes) {
         window.webkitRequestFileSystem(window.PERSISTENT, bytes, function(fs) {

冒頭で述べましたが、こちらのスクリプトを実行すると以下のようなメッセージが表示され、ユーザに対して許可を求めます。 保存要求
ただし、現在のchromeの仕様では要求ファイルサイズが「1024*1024」バイトまででしたら[PERSISTENT]形式でもユーザに対して許可を求めないようです。

保存したファイルを確認する

さて、ここでFileSystem APIで保存したファイルを確認してみましょう。Chromeのエクステンションに「HTML5 FileSystem Explorer」というツールがあります。このツールを使うと使用しているブラウザにどんなデータが保存されているか確認でき、また削除することもできます。

HTML5 FileSystem Explorer
ラジオボタンを切り替えることで、それぞれの保存形式のファイルについて確認することができます。

ファイルの書き込み

ファイルへの書き込みのサンプルを見てみましょう。

 function onloadInit() {
    navigator.webkitPersistentStorage.requestQuota(1024*1024*5, function(bytes) {
        window.webkitRequestFileSystem(window.PERSISTENT, bytes, function(fs) {
           fs.root.getFile('tmp.txt', {create: true}, function(fileEntry) {

               fileEntry.createWriter(function(fileWriter) {
                   fileWriter.onwriteend = function(e) {
                       console.log('書き込み完了');
                   };
           
                   fileWriter.onerror = function(e) {
                       console.log('書き込みエラー: ' + e.toString());
                   };
                   var blobData = new Blob(['hogehoge']);
                   fileWriter.write(blobData);
               });
           });
       });
    });
}

このサンプルを実行するとtmp.txtに[hogehoge]を書き込みを行います。ファイルにデータを書き込むにはBlobオブジェクトを使用して書き込みます。

var blobData = new Blob(['hogehoge']);

実行後に先ほど紹介した「HTML5 FileSystem Explorer」を実行してみましょう。ファイルサイズが8バイトになっているのが分かります。またファイルをクリックすると書き込んだ内容も表示されます。
HTML5 FileSystem Explorer2

ディレクトリを作成する

FileSystem APIはディレクトも作成することができます。ファイルを作成する際は「fs.root.getFile」でしたが、ディレクトリを作成する場合は「fs.root.getDirectory」になります。

function onloadInit() {
    navigator.webkitPersistentStorage.requestQuota(1024*1024*5, function(bytes) {
        window.webkitRequestFileSystem(window.PERSISTENT, bytes, function(fs) {
            // ディレクトリ作成
            fs.root.getDirectory('dir1', {create: true}, function(dirEntry) {
          console.log('ディレクトリ作成');
            });
        });
    });
}

またディレクトリの中にディレクトを作成していくこともできます。ただしその場合は、1つずつディレクトリを作成していく必要があります。
以下の例では配列に指定したディレクトリ名を入れ子にして作成しています。

function onloadInit() {
    navigator.webkitPersistentStorage.requestQuota(1024*1024*5, function(bytes) {
        window.webkitRequestFileSystem(window.PERSISTENT, bytes, function(fs) {
            // 作成するディレクトリの配列
            var dirArray = [ "dir1", "dir2", "dir3" ]; 
            createDir(fs.root, dirArray, onCreateDirHandler);
        });
    });
}

// ディレクトリ作成ハンドラ
function onCreateDirHandler(dirEntry, dirArray) {
    createDir(dirEntry, dirArray, onCreateDirHandler);
}

// ディレクトリ作成
function createDir(dirEntry, dirArray, callBack) {
    if (dirArray.length > 0) {
        dirName = dirArray[0];
        dirArray.shift();
        dirEntry.getDirectory(dirName, {create: true}, function(dirEntry) {
            callBack(dirEntry, dirArray);
        });
    }
}

実行後、「HTML5 FileSystem Explorer」で確認してみます。ディレクトリの中にディレクトリが作成されていることが分かります。
ディレクトリ

ファイルの削除

ファイルの削除はremoveメソッドを使用します。また、fs.root.getFileの引数は{create: false}に設定します。trueに設定するとファイルが無い場合に一度ファイルを作成してから削除されるという余計な処理がされてしまいます。

function onloadInit() {
    navigator.webkitPersistentStorage.requestQuota(1024*1024*5, function(bytes) {
        window.webkitRequestFileSystem(window.PERSISTENT, bytes, function(fs) {
            fs.root.getFile('tmp.txt', {create: false}, function(fileEntry) {
                // ファイル削除
                fileEntry.remove(function() {
                    console.log('ファイル削除');
                });
            });
        });
    });
}

ディレクトリの削除

ディレクトリの削除もファイル削除と同じでremoveメソッドを使用します。ただし、ディレクトリの削除では1点注意が必要です。削除しようとしているディレクトリ内にファイルなどがある場合はエラーとなってしまいます。例えば先ほど作成したディレクトリ「/dir1/dir2/dir3」を削除したい場合に以下を実行するとエラーが発生します。

function onloadInit() {
    navigator.webkitPersistentStorage.requestQuota(1024*1024*5, function(bytes) {
        window.webkitRequestFileSystem(window.PERSISTENT, bytes, function(fs) {
            fs.root.getDirectory('/dir1', {create: false}, function(dirEntry) {
                dirEntry.remove(function() {
                    console.log('ディレクトリ削除');
                }, errorHandler);
            });
        });
    });
}

function errorHandler(e) {
    console.log('書き込みエラー: ' + e.code);
}

ディレクトリ「/dir1/dir2/dir3」を削除する場合はdir3から順番に削除する必要があります。その場合は以下のようにdir3までのフルパスを指定します。これでdir3のディレクトリが削除することができます。

fs.root.getDirectory('/dir1/dir2/dir3', {create: false}, function(dirEntry) {
    dirEntry.remove(function() {
        console.log('ディレクトリ削除');
    }, errorHandler);
});

まとめ

いかたでしたでしょうか。今回はファイルの作成・削除、ディレクトリの作成・削除について説明しました。これを応用して他のAPIなどと組み合わせれば色々なことが出来るかと思います。