JavaScriptでローカルにファイルを保存する方法を調べたので、メモ。
動作確認はMac OS X10.9.2、Google Chrome 33で行っています(他のブラウザについては、参考リンクにもある JavaScriptからローカルファイルを作成する方法まとめ - あらびき日記 をご覧ください)。
Chromeでローカルにファイルを保存するには、File API: Writerを使います。
単純なテキストファイルをローカルに保存するサンプルは下記のようになります。
サンプルコード
<script type="text/javascript"> function writeToLocal(filename, content) { // chrome以外は弾く var ua = navigator.userAgent.toLowerCase(); if (ua.indexOf('chrome') == -1) { alert("This Page is Google Chrome only!"); } function errorCallback(e) { alert("Error: " + e.name); } function fsCallback(fs) { fs.root.getFile(filename, {create: true}, function(fileEntry) { fileEntry.createWriter(function(fileWriter) { fileWriter.onwriteend = function(e) { alert("Success! : " + fileEntry.fullPath); }; fileWriter.onerror = function(e) { alert("Failed: " + e); }; var output = new Blob([content], {type: "text/plain"}); fileWriter.write(output); }, errorCallback); }, errorCallback); } // クオータを要求する。PERSISTENTでなくTEMPORARYの場合は // 直接 webkitRequestFileSystem を呼んでよい webkitStorageInfo.requestQuota(PERSISTENT, 1024, webkitRequestFileSystem(PERSISTENT, 1024, fsCallback, errorCallback), errorCallback); } writeToLocal("hoge.txt", "foo\n"); </script>
サンプルコードの内容について、要点だけ説明します。
ファイルシステムの要求
まず、 webkitRequestFileSystem()によってファイルシステムを要求します。
第一引数にはwindow.PERSISTENT(永続データ)、もしくはwindow.TEMPORARY(一時データ)を指定します。
ここで注意なのがPERSISTENTを指定した場合で、データ保存許可をユーザから得なくてはいけません。
サンプルコードのwebkitStorageInfo.requestQuota()がそれで、ページ表示時に最上部に許可ダイアログが表示されます。ここで一度許可すると次回以降はrequestQuota()する必要はありません。
また、TEMPORARYを指定した場合にはrequestQuota()する必要はなく、単にwebkitRequestFileSystem()を呼べばよいです。
ファイル書き込み
fs.root.getFile()すると、内部的にファイルが作成されます。
最後に、Blobデータを作成し、fileWriter.write()でファイルに書き込みを行います。シンプルですね。
ただ、ここでもハマりポイントがあって、Blob作成にはBlob()を使いましょう。
他のページだとBlobBuilder()やWebKitBlobBuilder()を使っているものが多いですが、BlobBuilder()は非推奨、WebKitBlobBuilder()はChromeから既に削除されています!
作成されたファイルは、/Users/USERNAME/Library/Application Support/Google/Chrome/Default/File System/
以下に保存されます。
PERSISTANTで保存した場合は、上記ディレクトリ/(数字3文字のディレクトリ)/p
TEMPORARYで保存した場合は、上記ディレクトリ/(数字3文字のディレクトリ)/t
以下に保存されます。
その中で、さらに(数字2文字のディレクトリ)/(数字列だけの拡張子なしファイル)
に保存されます。なので、実はwriteToLocal()の第一引数で指定したファイル名はほぼ無意味です。
ただ、同じファイル名を指定すると同じファイルに保存され、違うファイル名を指定すると、数字が1増えたファイル名で保存されるようです。
まとめ
JavaScript+Google Chromeでファイル保存する方法はあるものの、ファイルの保存先が自由に選べなかったり(そりゃそうだが)、ファイル名を指定できなかったりで、使い勝手が悪いです。
ファイル保存先を指定するリンクを作成して、そこからファイルを保存する方法があるので、そのうちそのエントリも書きます。