ローカルファイルアクセス用Fileクラス

JavaScriptからローカルファイルにアクセスするためのXPCOM利用版のFileクラスを作ってみた。

使用例

d:\tmp\a.txtのFileオブジェクトをfに代入して読み書きする例。
readが読み出し。readしたあとはcharsetプロパティがセットされる。
writeが書き込み。現在セットされているcharsetで書き込む。writeで'a'オプションを使うと追記。
関係ないけどJavaScriptは常にバックスラッシュをエスケープする必要があるのがめんどくさい。

>>> f = new File('d:\\tmp\\a.txt')
[File D:\tmp\a.txt]
>>> f.read()
"あいうえお"
>>> f
[File D:\tmp\a.txt UTF-8]
>>> f.write('かきく')
>>> f.write('けこ','a')
>>> f.read()
"かきくけこ"

ファイル名を与えずにインスタンスを生成しておいて、後でダイアログで選択したファイル名をセットする例。
pickerメソッドを使うとファイル選択ダイアログを表示する。
ファイル名がセットされた状態でpickerメソッドを使うとそのファイル名がデフォルトになったダイアログになる。

>>> g = new File()
[File undefined]
>>> g.picker('Open')
[File D:\tmp\a.txt]
>>> g.read()
"かきくけこ"
>>> g.picker('Save').write('さしすせそ')
>>> g.picker('Open').read()
"さしすせそ"

コード本体

ここでは省略しているが、この間書いた文字コード変換メソッドを使っているのでそれも必要。

function File(path,charset){
  if(charset) this.charset = charset;
  if(!path) return;
  if(path.path) this.file = path;
  else{
    this.file = xpc('c','file/local;1','LocalFile');
    this.file.initWithPath(path);
  }
}
File.prototype.picker = function(mode){
  this.fp = this.fp || xpc('c','FilePicker;1');
  this.fp.init(window,null,this.fp['mode'+(mode||'Open')]);
  if(this.file){
    this.fp.displayDirectory = this.file.parent;
    this.fp.defaultString = this.file.leafName;
  }
  this.result = this.fp.show();
  if(this.result != this.fp.returnCancel) this.file = this.fp.file;
  return this;
}
File.prototype.read = function(){
  if(!this.file || this.result==1) return;
  this.input = this.input || xpc('c','network/file-input-stream;1');
  this.input.init(this.file,1,0,null);
  this.sinput = this.sinput || xpc('c','ScriptableInputStream;1');
  this.sinput.init(this.input);
  this.content = this.sinput.read(-1);
  this.sinput.close();
  this.input.close();
  return this.conv(this.charset || this.content.guess());
}
File.prototype.write = function(data,append){
  if(!this.file || this.result==1) return;
  this.output = this.output || xpc('c','network/file-output-stream;1');
  this.output.init(this.file,2|8|(append?0x10:0x20),0644,null);
  this.content = data.convTo(this.charset||'UTF-8');
  this.output.write(this.content,this.content.length);
  this.output.close();
  return this;
}
File.prototype.conv = function(charset){
  this.charset = charset;
  if(this.content) return this.content.convFrom(charset);
}
File.prototype.toString = function(){
  return '[File '+(this.file ? this.file.path : this.file)+(this.charset ? ' '+this.charset : '')+']';
}
function xpc(m,c,i){
  return Components.classes['@mozilla.org/'+c.toLowerCase()]
    [m[0]=='c' ? 'createInstance' : 'getService']
    (Components.interfaces['nsI'+(i||c.replace(/.*\/|;.*/g,'')
     .replace(/(^|-)(.)/g,function(a,b,c){return c.toUpperCase();}))]);
}