Chrome で FileSystem API

Clojure Library をインストールしたので、HTML5のFileSystem APIを使ってみようと思い、こちらのサイトの説明を参考にして遊んでみた。

 FILESYSTEM API について知る



 まず、各ブラウザの実装状況を調べてみた。書き込みまでサポートしているのはChromeだけらしい。メンドくさいけどChromeをインストールした。


 それから、解説記事を参考にして、FileWriterを使ってPERSISTENTストレージに書き込むコードを書いた。試しに動かすと、JavaScriptコンソールにNO_SUPPORTED_ERRとエラーが出る。調べてみると、Chromeに起動オプションをつけなければいけないらしい。ということで、次のAppleScriptを書いたappファイルを作って起動するようにした。

do shell script "/Applications/Google\\ Chrome.app/Contents/MacOS/Google\\ Chrome --unlimited-quota-for-files --allow-file-access-from-files > /dev/null 2>&1 &"

これで、NO_SUPPORTED_ERRは出なくなった。


 しかし、コンソールに、undefined が出ている。調べてみると、undefinedになっているのはWebKitBlobBuilderだ。


 どうやら、サイトの情報がすでに古くなっているらしい。かといって、他にまとまった説明のあるサイトも見当たらない。テキトーにググってみると、BlobBuilderインタフェースはdeprecatedになっていて、すでにchromeから削除されてしまっているらしい。これからは、直接Blobオブジェクトを使えとのお達しが出ているようだ。


 ところが、W3CのBlobオブジェクトの説明を見てみると、Blobオブジェクトはimmutableだとか書いてあって、ArrayBufferあたりを引数にするしかないらしい。メンドくさいなと思ってさらにぐぐってみたら、Blobコンストラクタに文字列の配列を渡すと、勝手にUTF8に変換してくれるらしい。W3Cのドキュメントを斜め読みしてもまったくそんな風には読めなかったのだけど、英語力のなさのせいだろう。


という訳で、ファイル書き込みのコードは次のような感じになった。

  function FirstTryToUseFileWriter() {
    //ファイルシステム要求成功時のコールバック
    function onInitFs(fs) {
      logger.info('Opened file system: ' + fs.name);
      //ファイルを作成する
      fs.root.getFile('log.txt', {create: true}, function(fileEntry) {
        //ファイル作成成功時のコールバック
        fileEntry.createWriter(function(fileWriter) {
          // Create a FileWriter object for our FileEntry (log.txt).
          fileWriter.onwriteend = function(e) {
            logger.info('Write completed.');
          };
          fileWriter.onerror = function(e) {
            logger.info('Write failed: ' + e.toString());
          };
          // Create a new Blob and write it to log.txt.
          var blobData = new window.Blob(['data to write']);
          fileWriter.write(blobData);
        }, errorHandler);
      }, errorHandler);
    }
    //エラーハンドラ
    function errorHandler(e) {
      var msg = '';
      switch (e.code) {
        case FileError.QUOTA_EXCEEDED_ERR:
          msg = 'QUOTA_EXCEEDED_ERR';
          break;
        case FileError.NOT_FOUND_ERR:
          msg = 'NOT_FOUND_ERR';
          break;
        case FileError.SECURITY_ERR:
          msg = 'SECURITY_ERR';
          break;
        case FileError.INVALID_MODIFICATION_ERR:
          msg = 'INVALID_MODIFICATION_ERR';
          break;
        case FileError.INVALID_STATE_ERR:
          msg = 'INVALID_STATE_ERR';
          break;
        default:
          msg = 'Unknown Error';
          break;
      };
      logger.info('Error: ' + msg);
    }

    //5MBのクォータを要求
    size = 5 * 1024 * 1024;
    window.requestFileSystem  = window.requestFileSystem ||
                                window.webkitRequestFileSystem;
    window.webkitStorageInfo.requestQuota(window.PERSISTENT, size,
      //クォータ要求成功時のコールバック
      function(grantedBytes) {
        //ファイルシステムを要求
        window.webkitRequestFileSystem(window.PERSISTENT,
                     grantedBytes, onInitFs, errorHandler);
      },
      //クォータ要求のエラーハンドラ
      function(e) {
        logger.info('Error', e);
      });
  }

 非同期でやたらとコールバックを使うAPIになっているので、とても使い勝手が悪い。OSレベルのAPIと似たような感じだ。もしかすると、高レベルAPIも計画されているのかも知れないけど、このレベルでこんだけ決まるのが遅いんじゃ望み薄。また、どっかの非標準ライブラリができちゃって、ライブラリの選定に悩む状況になるのは必至。


やはり、Web関係の開発はメンドくさい。