JavaScriptからローカルファイルを作成する方法まとめ
久しぶりに JavaScript と戯れたいなぁと思ったので JavaScript からローカルファイルを作成する方法をまとめてみました。
私の知る限り、Internet Explorer(ActiveX)、Firefox(XPCOM)、Google Chrome(File API: Writer)の3ブラウザがローカルファイルの作成に対応しています。
※File API: Writer は意味合いが違う気がしますが・・・
– 2012-04-12 追記 –
当時の正確なバージョンはわかりませんが、時期的に IE8、Firefox 5、Google Chrome 12 で動作確認していると思われます
———————
細かいことは後で説明するとしてローカルファイルを作成するコードは例えば次のようになります。
※IE、Firefox の場合は /tmp(Unix), C:\tmp(Windows)以下にファイルが作成されることが前提です
<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN' 'http://www.w3.org/TR/html4/loose.dtd'>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<script type="text/javascript">
function writeToLocal(filename, content) {
var ua = navigator.userAgent.toLowerCase();
try {
if (ua.indexOf('firefox') != -1) { // Firefox
filename = (ua.indexOf('windows') != -1 ? 'C:\\tmp\\' : '/tmp/') + filename;
// ローカルファイルにアクセスする権限を取得
// fileスキームじゃない場合は about:config で
// signed.applets.codebase_principal_support を true にする必要あり;
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
// ファイルコンポーネントの取得+ローカルファイル操作用のインターフェイスの取得;
var file = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
file.initWithPath(filename);
var fileStream = Components
.classes['@mozilla.org/network/file-output-stream;1']
.createInstance(Components.interfaces.nsIFileOutputStream);
// ファイルが存在しない場合は664の権限で新規作成して書き込み権限で開く
// cf. https://developer.mozilla.org/en/NsIFileOutputStream
// http://www.oxymoronical.com/experiments/apidocs/interface/nsIFileOutputStream;
fileStream.init(
file,
0x02 | 0x08, // 0x01: 読み取り専用, 0x02: 書き込み, 0x03: 読み書き, 0x08: 新規作成, 0x10: 追記
0664, // mode
0 // 第4引数は現在サポートしていないとか
);
// cf. http://www.oxymoronical.com/experiments/apidocs/interface/nsIConverterOutputStream
var converterStream = Components
.classes['@mozilla.org/intl/converter-output-stream;1']
.createInstance(Components.interfaces.nsIConverterOutputStream);
converterStream.init(
fileStream,
'UTF-8',
content.length,
Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER
);
converterStream.writeString(content);
converterStream.close();
fileStream.close();
alert('書き込みが完了しました!');
} else if (ua.indexOf('chrome') != -1) { // Google Chrome
// 起動オプションに --unlimited-quota-for-files --allow-file-access-from-files をつける必要あり
function errorCallback(e) {
alert('Error: ' + e.code);
}
function fsCallback(fs) {
fs.root.getFile(filename, {create: true}, function(fileEntry) {
fileEntry.createWriter(function(fileWriter) {
fileWriter.onwriteend = function(e) {
alert('書き込みが完了しました!');
};
fileWriter.onerror = function(e) {
alert('Failed: ' + e);
};
var bb = new WebKitBlobBuilder();
bb.append(content);
var output = bb.getBlob('text/plain');
fileWriter.write(output);
}, errorCallback);
}, errorCallback);
}
// 現時点ではたぶん第1引数はPERSISTENTもTEMPORARYディレクトリ名が異なるだけだし、
// 第2引数は極端な話0でもOK
webkitRequestFileSystem(PERSISTENT, 1024, fsCallback, errorCallback);
} else if (ua.indexOf('msie')) { // MS IE
filename = 'C:\\tmp\\' + filename;
// インターネットオプションで「スクリプトを実行しても安全だとマークされていない
// ActiveX コントロールの初期化とスクリプトの実行(セキュリティで保護されていない)」
// を有効にする必要あり
var fso = new ActiveXObject('Scripting.FileSystemObject');
// ファイルを新規作成して書き込みモードで開く (文字コードはUTF-16)
// cf. http://msdn.microsoft.com/ja-jp/library/cc428044.aspx
// http://msdn.microsoft.com/ja-jp/library/cc428042.aspx
var file = fso.OpenTextFile(
filename,
2, // 1: 読み取り専用, 2: 書き込み, 8: 追記
true, // ファイルが存在しなければ新規作成するかどうか
-1 // -2: OSのデフォルト文字コード, -1: UTF-16, 0: ASCII
);
file.Write(content);
file.Close();
alert('書き込みが完了しました!');
/*
* ADODB.Stream を使う場合(レジストリをいじっても何故か書き込めない・・・)
*/
// var adodbStream = new ActiveXObject('ADODB.Stream');
// adodbStream.type = 2; // テキストファイル(バイナリは1)
// adodbStream.charset = 'UTF-8';
// adodbStream.open(filename);
// adodbStream.writeText(content);
// adodbStream.saveToFile(filename, 2); // 上書き保存(1だと新規作成のみが対象)
// adodbStream.close();
} else {
alert('エラー: ローカルファイルへの書き込み方がわかりません・・・');
}
} catch (e) {
alert('Error: ' + e);
}
}
writeToLocal('test.txt', 'これはJavaScriptが作成したファイルだよ!\n');
</script>
</head>
</html>
かなり詳しくコメント書いてるんであまり説明の必要もないと思いますが、極簡単な説明と注意点だけ書きます。
File API も含めてどれもセキュリティ的によろしくないと思うので、テストで試してみるにしても終わったら元のオプションに戻すことをお勧めします。
IE
ActiveX を利用しています。ActiveX はご存知ブラウザだけでは実現不可能な機能を可能にする”便利”な機能です。
セキュリティオプションで「スクリプトを実行しても安全だとマークされていない ActiveX コントロールの初期化とスクリプトの実行(セキュリティで保護されていない)」を有効にする必要があります。
※fileスキームの場合は必要なし(かも)
UTF-8 で 出力しようとすると ADODB.Stream を使ったり Utf8Lib.Utf8Enc を使えば可能みたいなんですが、レジストリやセキュリティオプションをいじっても「Error: オートメーションサーバーはオブジェクトを作成できません。」というエラーが出てしまいました。1
Firefox
XPCOM (Cross Platform Component Object Model) を利用しています。Wikipediaによれば
XPCOM(Cross Platform Component Object Model)は、Mozillaプロジェクトにおいて開発されているクロスプラットフォームなコンポーネント技術である。
とのことです。Firefox のアドオンで多様な機能を提供できるのは XPCOM を使っているから(のはず)です。
about:config で signed.applets.codebase_principal_support を true にする必要があります。
※fileスキームの場合は必要なし
Chrome
File API: Writer を利用しています。File API を利用することでドラッグ&ドロップしたファイルをページに表示したりサーバにアップしたりできることはよく知られていると思いますが、ローカルに書き込みもできるように話が進んでいるようです。
File API: Writer を現時点で実装しているのは主要ブラウザではおそらく Chrome だけです。
Chrome で File API: Writer の機能を利用してローカルに書き込むには起動オプションに –unlimited-quota-for-files –allow-file-access-from-files をつける必要があります。
※近々デフォルトで有効になるのではないかと
– 2012-04-12 追記 –
Google Chrome 18 では File API: Writer の機能を使うのに起動オプション不要でした。
———————
Windows 7 の場合
コマンドプロンプトから次のコマンドを実行します(USERNAMEは自分のユーザ名を使用してください)
> cd C:\User\USERNAME\AppData\Local\Google\Chrome\Application
> chrome.exe --unlimited-quota-for-files --allow-file-access-from-files
出力されるファイルは
C:\User\USERNAME\AppData\Local\Google\Chrome\User Data\Default\FileSystem\Persistent
以下に作成されます。
Mac OS X の場合
端末から次のコマンドを実行します。
$ open -a "Google Chrome" --args --unlimited-quota-for-files --allow-file-access-from-files
出力されるファイルは
/Users/USERNAME/Library/Application Support/Google/Chrome/Default/FileSystem/Persistent
以下に作成されます。
– 2012-04-12 追記 –
Google Chrome 18 の時点では /Users/USERNAME/Library/Application Support/Google/Chrome/Default/File System 以下に作成されるようになっていました
———————
以上のようにデータをクライアント側に保存しておけばオフライン作業ができたり、簡単なアプリケーションであれば JavaScript のみで完結できたりと夢が広がりますね!
File API に興味がある方はこんなエントリーもありますよ!
Filefoxでファイルの非同期アップロード with 複数パラメータ - あらびき日記
参考
ActiveX 関係
- いろんな文字コードでファイルを読み書きするにはADODB.Stream - 今日覚えたこと
- ADODB.Stream を使ったファイルの読み書き - by AOK
- javascript - Writing UTF8 text to file - Stack Overflow
- Internet Explorer で ADODB.Stream オブジェクトを無効にする方法
XPCOM 関係
- XPCOM インターフェイス - MDN Docs
- 4章:XPCOM活用術 - Firefox拡張機能開発チュートリアル (XHTML)
- File I/O - MDN Docs
- javascript - How to sign script or webpage requiring UniversalXPConnect privilege - Stack Overflow
- ローカルファイルへの書き込み(その2) - awacio.log
File API: Writer 関係
- File API: Writer, Directories and System
- File API: Writer
- File API: Directories and System
- Exploring the FileSystem APIs
- Simple test to FileSystem APIs (HTML5) ― Gist
-
regedit で \HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\ActiveX Compatibility{00000566-0000-0010-8000-00AA006D2EA4} の Compatibility の値を0にすると対処できるようですが無理でした ↩