JavaScript File オブジェクト の案
by Henri Torgemane,
Michael Ang <mang@subcarrier.org>,
and Vladimir Livshits <val4@cornell.edu>

この文書は、JavaScript File オブジェクトについての API を記述している。 多くの API が、実装された (だがテストしていない)が、 また終わっていない作業がある。 mailto:nboyd@atg.comに意見を送ってください。

JavaScript で書いた多くのスクリプトは、I/O 機能、特に普通のファイルへのアクセスを必要としている。 この文書は、ホストの実装が実装することが出来る、そのような File オブジェクトを説明している。

そのインターフェースは、Server Side JS File オブジェクトと Java File オブジェクトを混ぜ合わせたもので 既にある JavaScript の暗黙のしきたり (例えば、reaLine ではなく readln) に従おうとしている。

File オブジェクトは、ファイル内のデータへのアクセス方法を二つ提供している。 文字を基にしたテキスト志向のアクセスと、バイトを基にしたバイナリ志向のアクセス。 テキストモードでは、最大文字列長は現在 256 である。 さまざまなエンコーディングが許される。ASCII、UTF8 (unicode)、と UCS2 (binary) が現在サポートされている

実装は現在ほとんど NSPR の PRFileDescを基にしている (申し訳ないがこれに対する公開リンクはまだない) が、 C の標準 FILE タイプを基にファイルを作成することを許すという裏口もある。 これは、標準ストリーム stdin、stdout、と stderr を基にした JavaScript のファイルを初期化する機能の提供に使われる。 パイプの実装もこれによって行われている。 だが、FILE式のファイルでは、操作がすべて一様にどこでもサポートされるわけではない。 結局のところ、異なったプラットフォーム間の違いを隠すのが、NSPR の目標だ。 


0.0 Changelog

  • 1/18/98 - volodya が、 追加あるいは修正された特徴を API に文書にするという小さな変更をたくさん追加した。 ネイティブファイルハンドリング、さまざまな場合のこのオブジェクトの作用の仕方などについて説明を追加した。 特に、現在のほとんどの情報に付いては status を見なさい。
  • 12/18/98 - mangは mozilla.org の仕事を暫く休む。 暫定オーナーはNorris Boyd
    • nsFileSpec email thread を追加。 File オブジェクトは、現在のファイル名操作コードに代わって機能性として nsFileSpec を使うべき。
    • 追加プロパティー、appendautoFlushreplace。 これらのプロパティーは、破棄された mode を置きかえる。 mccabe@netscape.comより。
    • 未解決の問題/TODOに深い考えを更に追加。
  • 12/09/98 - ファイルが親を持っていなければ、parent プロパティーに そのファイル自身を入れるのではなく、null をセットするようにした。 fur@geocast.comより。
  • 12/07/98 - indelete は予約済みの識別子。 ininputに、outoutput に、 errerror に、deleteremove に変更。 brendan@netscape.comより。

1.0 ファイル名

    ファイル名は、実装定義のフォーマットを持つ文字列をして指定される。 標準 "file:" URL の使用が推奨される。

    使用可能なプレフィックス文字列の例としては、Unix のルートディレクトリを示す "/" や、 Windows のドライブ文字を指定する "c:" や、file URL を示す "file:" がある。

    ファイルが作られると、前と後ろのスペースはファイル名から取り除かれる。 だから、new File(" abc.txt    ") は、 abc.txt と呼ばれるファイルを作る。 '|' で始まり終わるファイル名は Perl 風にパイプと解釈される。

    次のような事が可能だろう:

      var mail = new File("|/usr/bin/mail foo@bar.com");
      mail.writeln("I love JavaScript.\nPipe support is especially good!");
      mail.close();

2.0 File コンストラクターのプロパティー

     
    File File コンストラクターメソッド
    input 標準入力を表す File オブジェクト。
    output 標準出力を表す File オブジェクト。
    error 標準エラー出力を表す File オブジェクト。
    currentDir カレントディレクトリを参照する File オブジェクト。このプロパティーは設定されるかもしれない。
    separator システムの名前区切り文字。

    注: 最初の木のプロパティーは、特定の環境下でしか使えないようにするべきかもしれない。 例えばブラウザコンテキストでは不可能など。 例えば isFile のようなメソッドの中には、そのような環境の一つの元で呼ばれると、 エラーをかえすものがあることを留意しなさい。

2.1 File インスタンスのプロパティー

     
    name ファイルの名前が入る。
    path ファイルへの基準パスが入る。
    length ファイル内の文字の数が入る。
    parent ファイルを含むディレクトリが入る。
    type データの型かファイル内に含まれているエンコーディングを指定する文字列が入る。 現在は "ascii"、"utf8" (UTF8)、 あるいは "ucs2" (UCS2)。
    mode ファイルモードが入る。
    position ファイル内での現在のオフセットが入る。このプロパティーは設定されるかもしれない。
    isFile ファイルが通常のファイルなら true。
    isDirectory ファイルがディレクトリなら true。
    exists ファイルが存在するなら true。
    isOpen ファイルのオープンに成功したなら true。
    isNative パイプで標準ストリームに対しては true。
    lastModified 最後に変更された時を表す Date オブジェクトが入る。
    canRead ファイルが読み込み可能なら true。
    canWrite ファイルが書きこみ可能なら true。
    canAppend ファイルが追加モードか示すフラグが入る。
    canReplace ファイルが置き換えモードか示すフラグが入る。
    hasRandomAccess "position" プロパティーを使用可能か示すフラグが入る。
    hasAutoFlush ファイルが自動フラッシュモードか示すフラグが入る。

2.2 インスタンスメソッド

     
    open(type,mode) ファイルを開く
    close() ファイルを閉じる
    flush() ファイルへの送信を待つデータをフラッシュする
    seek(numChars) 次の numChars 分の文字をスキップする
    read(numChars) numChars 分の文字を読み、文字列に入れる
    readln() ファイルから一行分の文字を読む
    readAll() ファイル内に残っている行すべてを読み、文字列の配列をかえす
    write(arg0,arg1,...,argn) パラメーターを文字列としてファイルに書きこむ
    writeln(arg0,arg1,...,argn) writeと同じで、現在のプラットフォームの改行区切り文字を追加する
    writeAll(Array) オブジェクトの配列を順にファイルに書きこむ
    remove() ファイルかディレクトリを削除する
    copyTo(filename) ファイルの内容を別の場所にコピーする
    renameTo(filename) ファイルを移動/名前の変更をする
    list(filter) ディレクトリ内のファイルリストを得る。
    mkdir() 新しいディレクトリを作成する
    toString() ファイルへの基準パスをかえす
    toURL() 可能ならファイル名を "file:" URL でかえす

3.0 File コンストラクターのプロパティー

    File

    File コンストラクター。filename をただ一つの引数として期待する。 filename の前に "file://" を置くことも可能で、置いても取り除かれる。 引数を与えられなかったら、現在のワーキングディレクトリをかえすファイルオブジェクトとする。

    input

    標準入力ストリームを表す File オブジェクト。特定の環境下で初期化される。

    output

    標準出力ストリームを表す File オブジェクト。特定の環境下で初期化される。

    error

    標準エラーストリームを表す File オブジェクト。特定の環境下で初期化される。

    currentDir

    このプロパティーには、カレントディレクトリを指す File オブジェクトが入る。 このプロパティーに代入すると、カレントディレクトリーが変更される。 次のような構文がサポートされている。

      File.currentDir = new File("/");
          これは機能上は次と同じ
      File.currentDir = "/";
    separator

    システムの名前区切り文字。例えば、Unixでは "/"。

3.1 File インスタンスのプロパティー

    name

    このプロパティーにはファイル名が入る。ストリームに対しては、"Standatd input(output/error) stream" と定義される。 パイプに対しては undefined。

    path

    このプロパティーにはファイルへの基準パスが入る。 ストリームに対しては、"Standard input(output/error) stream" と定義される。 パイプに対しては、パイプを作るのに使用したパスをかえす。初めとそれに続くスペースは取り除かれる。

    length

    ディレクトリに対しては、カレントディレクトリと親ディレクトリエントリーを数えないファイルの数である。 ファイルに対しては、このプロパティーはファイル内の文字の数が入る。 パイプと標準ストリームに対しては undefined。

    parent

    このプロパティーには、そのファイルを含んでいるディレクトリを指す File オブジェクトが入る。 そこファイルに何にも含まれていなければ (ルートディレクトリ)、プロパティーは null である。 パイプと標準ストリームに対しては undefined。

    type

    このプロパティーには、ファイルが開かれた時使われていたデータタイプかエンコーディングを指定する文字列が入る。 指定されたテキストエンコーディングサポートは、"ascii"、"unicode"、と"binary" である。 ディレクトリと閉じてしまったファイルに対しては undefined。

    mode

    このプロパティーにはファイルのモードが入っている。 属性を繰り返したり ("read,read")、無視される属性があったりすると、 オープンに失敗しなかったものと少々異なることが有り得る。 ファイルが閉じられていると undefined をかえす。

    position

    このプロパティーには、ファイル内の現在のオフセットが入る。 これだけが、設定されてもよいプロパティーだ。 ファイルがランダムアクセスモードでないか、パイプや標準ストリームだと、このプロパティーは undefined である。 閉じてしまったファイルに対しても undefined である。 このプロパティーを設定するとファイル上で seek 操作が行われる。

    isFile

    ファイルが世紀のデータファイルなら、このプロパティーには true が入る。 パイプと標準ストリームに対しては false。 注: いくつかのファイルタイプに対して (例えば unix の名前付きパイプ)、"isDirectory" と "isFile" の両方が false をかえすかもしれないプラットフォームもある。

    isDirectory

    ファイルがディレクトリならこのプロパティーは true が入っている。 パイプと標準ストリームに対しては false。

    exists

    ファイルが存在するなら、このプロパティーは true と等しい。 パイプと標準ストリームに対しては false。

    isOpen

    ファイルをうまく開き、開いた状態のままだと、このプロパティーには true が入る。 標準ストリームとパイプはデフォルトで開かれ、開く必要が無いことを心にとめておきなさい。

    isNative

    パイプと標準ストリームに対しては、このプロパティーには true が入る。

    lastModified

    このプロパティーには、ファイルが最後に編集された時を表す Data オブジェクトが入る。 パイプと標準ストリームに対しては undefined。

    canRead

    ファイルが読み出し可能なら、このプロパティーには true が入る。 ファイルが開かれたモード (もし開かれたのなら) は考慮される。 File.input に対しては true で、他のストリームに対しては false。 '|' で始まるパイプに対して true で、他は false。

    canWrite

    ファイルが書き込み可能なら、このプロパティーには true が入る。 ファイルが開かれたモード (もし開かれたのなら) は考慮される。 File.output と File.error に対しては true で、File.input に対しては false。 '|' で終わるパイプに対しては true で、他は false。

    canAppend

    ファイルが追加書き込みように開かれたのなら、このプロパティーには true が入る。 パイプと標準ストリームに対しては false。閉じてしまったファイルに対しては undefined。

    canReplace

    ファイルが置き換えフラグを与えられて開かれているのなら、このプロパティーには true が入る。 パイプと標準ストリームに対しては false。閉じてしまったファイルに対しては undefined。

    hasRandomAccess

    このプロパティーには、ファイルがランダムアクセスモードで開かれているかを示すフラグが入る。 つまり、"potition" プロパティーは読み出しと設定が可能である。 パイプと標準ストリームに対しては false。閉じてしまったファイルに対しては undefined。

    hasAutoFlush

    ファイルが自動フラッシュモードだと、このプロパティーには true が入る。 これが true と設定されると、毎度の writeln 呼び出しでストリームをフラッシュする。 パイプと標準ストリームに対しては false。閉じたファイルに対しては undefined。

3.1.1 ディレクトリのための特別なプロパティー

    ディレクトリを表す File オブジェクトは、ディレクトリ内に含まれるファイルを表す追加プロパティーを得る。

    これらのプロパティーはディレクトリ内のファイルのように同じ名前を持つ。
     
    myDir = new File("some/directory");
    myFileInDir = myDir.foo;

    名前付きプロパティールックアップを 通常のプロパティー名としては不正な名前を持つファイルを指すのに使うことが出来る。 

    mySameFileInDir = myDir["foo"];
    myOtherFile = myDir["some long filename with spaces and such"];

3.2 インスタンスメソッド

    open(type,mode)

    mode が指定されなかった場合、通常のファイルに対して使われるデフォルトの mode は、 "read,append,create" である。パイプは作成時に、 パイプの形式によるが "read" か "write" をデフォルトの mode として自動的に開かれる。 type が指定されなかった場合、デフォルトの type は "text" である。
     
    有効な mode (合成可能)
    read 読み出しのためにファイルを開くと指定する。
    write 書き込みのためにファイルを開くと指定する。
    readWrite 読み出しおよび書き込みのためにファイルを開くと指定する。
    randomAccess 読み出しおよび書き込みのためにファイルを開くと指定する。
    append ファイルポインターの位置をファイルの最後に置く。
    autoflush 改行文字が書かれたら出力に自動的にフラッシュするように頼む。
    replace ファイルを開く前に内容を消去する。

    "create=yes, append=yes" などの書式も使うことが出来る。 大文字小文字が違うのに注意してください。
     

      注:
      • "read" と "write" の両方がセットされると、"readWrite" は自動的にセットされる。
      • バイナリファイルに対して "randomAccess" は true とセットされる。
      • "autoflush" はデフォルトで true。
    有効な type
    "text" デフォルトのファイルエンコーディングを使ってテキストアクセス用にファイルを開く。
    "binary" バイナリアクセス用にファイルを開く。
    "unicode" Unicode アクセス用にファイルを開く。

    ファイルがネイティブファイルやディレクトリだと、警告を出す。 この場合両方とも戻り値は true である。ファイルがネイティブでなく既に開かれていると、 警告が生成されファイルは再び開かれる。 ファイルの先頭に行きたい場合などで意味をなすが、 かわりに seek を使うことが出来るだろう。

    close()

    このメソッドはファイルを閉じる。ファイルが開かれていなかったりネイティブファイルだと、 警告を出し、false をかえす。 開かれているファイルオブジェクトがスコープの外に出たとき、そのオブジェクト上でこのメソッドは自動的に呼ばれる。

    remove()

    このメソッドは、ファイルを削除するか、引数として与えられたディレクトリを削除する。 通常ディレクトリで削除が呼ばれたとき、ディレクトリが空のときしか削除されない。 ファイルを開いていると失敗する。

    copyTo(filename)

    このメソッドは、ソースファイルのそのまま目的のファイルへコピーしようと試みる。 ソースファイルが存在しなかったり、ディレクトリだと失敗するだろう。

    renameTo(filename)

    このメソッドは、ファイルを移動/名前の変更をする。ファイルが開かれていると失敗する。

    flush()

    このメソッドは、ファイルの出力バッファーのフラッシュを強制する。 ファイルが閉じられていたら失敗する。

    seek(numChars)

    このメソッドは、現在のファイルに対するアクセスモードによるが、次の numChars 分の文字列かバイト列をスキップする。 ファイルが閉じられていた場合、この操作を行う前に開かれる。 この関数は、正負両方のパラメーターを受け付ける。 ディレクトリで呼ばれたら、警告を報告し、undefined をかえす。 この操作が成功すると、ファイル内の現在の位置をかえす。

    read(numChars)

    このメソッドは、numChars 分文字を読みこみ、文字列でかえす。 読みこむ文字列の数が numChars より少ない場合、読めるだけかえされる。 ファイルが EOF にあると、null がかえされる。

    readln()

    このメソッドは、行/ファイルの終わりがなるまで文字列を読み、 それらの文字列に対して文字列を (end of line 文字を一切除いて) かえす。

    readAll()

    このメソッドは、ファイルの残りを読み込み、ファイルの各行に対してスロット付きの配列をかえす。

    write(arg0,arg1,...,argn)

    このメソッドは、各引数を文字列に変換し、ファイルに (セパレーターなしに) 書きこむ。

    writeln(arg0,arg1,...,argn)

    このメソッドは write と似ているが、最後の引数を出力した後プラットフォーム依存な EOF を追加する。

    writeAll(Array)

    このメソッドは引数に配列を取り、各要素ごとに writeln() を呼ぶ。

    list(filter)

    このメソッドは配列をかえす。ファイルがディレクトリなら、 そのディレクトリ内の各ファイルに対してスロットが作成され、 そのファイル名のプロパティーも作成される。 両方ともファイルを参照する File オブジェクトを指す。

    filter は、関数が正規表現でなければならないオプションの引数で、 配列のフィルターに用いられる。 引数が正規表現なら、配列にはパターンにマッチしたファイルしか入らない。 引数が関数なら、ファイル名を引数として与えたとき、関数が true をかえしたファイルしか配列には入らない。
     
    File.currentDir.list( function (name) { return name.length==3; } );

    カレントディレクトリで名前が三文字のファイルしかかえさない。 

    mkdir()

    このメソッドは、ファイルディレクトリ内にディレクトリを作成しようと試みる。 例えば、

      f = new File("c:\\")
      f.mkdir("win95")
    c:\win95\ を作成する。この断片も同じ事をする。
      f = new File("c:\\user.txt")
      f.mkdir("win95")
    toString()

    このメソッドは、ファイルに対する基準パスをかえす。

    toURL()

    ファイル名を "file:" URLとしてかえす。パイプと標準ストリームに対しては undefined。


4.0 遊んでみたい

大げさな免責条項: ハードドライブが消され無茶苦茶に破壊される覚悟が出来ていなければ、File オブジェクトで遊ぶなかれ! 今は大体上手く動いているが、保証はない。
     
    現在 File オブジェクトは、define を使ってコア JS engine 内へビルド可能である。 これはよくない。いったん XPCOM が落ち着いたら、File オブジェクトは COM 化するべきだ。

    File オブジェクトで遊ぶ/をハックするには、最新で (通常は) 一番良い JavaScript を 次のように CVS を使って入手しなさい。

    cvs co -rSpiderMonkeyDev_BRANCH mozilla/js/src

    JavaScript の開発進行中のブランチを入手するのだが、これは安定性にほとんど保証がないと警告しておく。

    File オブジェクト付きで (例えば UNIX 上のリファレンスインタプリターを) ビルドするには、 ビルド時に JS_HAS_FILE_OBJECT を define しなさい。 NSPR に対してビルドする必要もあり、JS_THREADSAFE を define することでこれは出来る。

    cd mozilla/js/src
    gmake -f Makefile.ref JS_THREADSAFE=1 JS_HAS_FILE_OBJECT=1

5.0 状態

    コードの状態:
    • コードはすべて jsfile.[c|h|msg] にある。とても良い状態にある。 少なくとも1999年12月半ばよりはずっとよい状態である。 まだ冗長な部分の削除、マクロの追加などをする機会がある。
    • 徐々に、最重要機能は実装さてテストされている。 ファイルのオープン、クローズ、読み出し、書き込みなどを含む。 より多くの例については、テスト一式の中の nspr_files.js を見なさい。
    • この提案で説明したメソッドとプロパティーは全部実装したと思う。 必ずしもどんなプラットフォームでも動くとは限らない。 特に、誰も Mac でこれをビルドしようとしていない。 注: パイプや場合によっては標準ストリームのような機能が Mac では使用できるようにならない。 NSPR の機能でさえ全部は動かないかもしれない。 Mac が含んでいるどれが必要なのかさえはっきりしない。
    • コードについて言うと、File オブジェクトのメソッドの多くはとてもしっかりテストされている。 低水準のファイルアクセスを取り扱うコードにまだ予測のつかないバグがあるだろう。 そのコードはまた、最適化されていない。割と大きなファイルのコピーにしばらくかかる。 ファイル名の操作は書きなおされた。 これと John McMullen が書いたものを合体させるという話があり、 一度彼ら (NSPR な人々, Brendan) が NSPR の一部であるべきで実装言語にどれを使うか考え出したら、それほど大変な話ではないだろう。 これについては netscape.public.mozilla.xpfe で議論がある。
    • 機能の多くをカバーするテスト一式がある。 だが、オブジェクトを酷使したとき潜在的なバグが多くでるだろう。 このバグは発見は難しいが簡単に修正できる。
    • コードの多くは、エラー状態を捕捉しエラーメッセージか警告を生成する目的に用いられる。 エラーコードについては jsfile.msg を見なさい。
    すべきこと:
    • エラーが起きたとき、例外を生成すべき。例外の書式はどうするべきだろう? 警告を報告する関数もあるし、エラーとなるものもある。 最終的には、すべて例外となるべき。
    • エラーメッセージを少し片付けるべき
    • セキュリティーコールバックをコードに入れるという話がある。 この目的のために SECURITY_CHECK マクロが残っている。 それは現在空の文字列として define されており、再 define の必要がある。 このマクロは、操作の名前をパラメーターの一つとして取り、その名前は現在メソッド名と一致しているが、 分解してグループ (read、write、exist など) に分けられるはずだ。 セキュリティーチェックは、処理手順にアクセスする個々のメソッドとプロパティーのレベルで実装されており、 根本的な実行関数のレベルで実装されているのではない。 なぜなら、  実行関数はコード内で別の場所から呼ばれる可能性があり、 私たちはセキュリティーチェックの階層化を望んでいないはずだから。 これについては Norris に質問しなさい。
    • RDF は JS に影響するようになる (GuhaClayton に聞きなさい)。 現在私たちは、JavaScript ファイルコンストラクタに RDF のなんとかという物を取ってこさせて、 普通の JS File オブジェクトをかえさせたい。 それはつまり、RDF を ファイルシステムを ナビゲートする のに使い、 File オブジェクトを読み書きなどに使うだろうという事。
    • js_canonicalPath(...) をどうすべきか考える。この処理手順は、 ".././blah/../../dir/file.txt" のように与えられたファイル名を解決する。 実際には必要ないと思う。ファイルシステムがこの名前を自動的に解決するから。 (最後に fopen 呼び出しの結果皆除去される) この処理手順は Mac 互換ではなく、潜在的に奇妙な問題や弱いリンクの問題があるかもしれない。 コード内で、マクロ RESOLVE_PATH を探しなさい。 この処理手順は、最初と最後のスペースを取り除いたりといった他の事もする。 js_absolutePath(...) へ移す必要があるかもしれない。
    • Purify を通してコードを実行するのは良い。
    • jsstr.h にある js_escape をコードで使っている。 何時の日か jsstr.h からそれは消え、クライアントへ移動するだろう。 そしてこのコードがビルド出来なくなる...
    • (?) nsFileSpec の機能を NSPR に巻き込むのに NSPR グループを得る。 上の議論を見なさい。外部コードが既に大体動いているので、 これが私たちのしたかったことなのかまだ完全には明らかではないが、 調べる価値はある。
    • (?) XPCOM 化 -- まただが、これにより受ける恩恵がはっきりしないが、 これは大幅な改訂が必要である。
    • (?) Java での実装ははっきりしない。 何故なら、LiveConnect + java.io.File で既にこの機能はある。
    • (?) api をソケットなどの使用が出来るように拡張する。(機能は既に PRFile 内にある。) 何のために必要なのかはっきりしないが、簡単に出来る。どうですか?
    • (?) 低水準ファイルアクセス機能は、能率的でないだろう (js_FileRead(..) などを見なさい)。 比較的小さなファイルのコピーにはしばらくかかる。 最適化できるだろう。既にきちんとバッファリングしているが。


    とりとめもない思索:

    • サーバーの領域にいる誰かが、同様のもの (Server-side JS?) を書こうとしていて、 XPCOM なファイルオブジェクトもどこかにあるようだ。 (Clayton に聞きなさい)


Norris Boydに質問しなさい。
Last modified: Fri Dec 18 20:47:48 PST 1998