このセクションでは、 Forth 内でファイルを使用する方法について簡単に説明します。 それは 5 つの簡単なステップに分かれています:
こちらも参照ください: General files
s" foo.in" r/o open-file throw Value fd-in
s" foo.out" w/o create-file throw Value fd-out
使用可能なファイル・モードは、 読み取り専用アクセスの場合は r/o 、 読み取り/書き込み アクセスの場合は r/w 、書き込み専用アクセスの場合は
w/o です。 必要に応じて、 読み取りと書き込みの両方のファイルを r/w で開くこともできます。 すべてのファイル用ワードはエラーコードを返します。
ほとんどのアプリケーションでは、 throw
を使用してエラー・コードを外部のエラー・ハンドラーに渡すのが最善(best)です。
開いたり(opening)割り当てたり(assigning)するためのワードが必要な場合は、 以下のように定義します:
0 Value fd-in 0 Value fd-out : open-input ( addr u -- ) r/o open-file throw to fd-in ; : open-output ( addr u -- ) w/o create-file throw to fd-out ;
使用例:
s" foo.in" open-input s" foo.out" open-output
256 Constant max-line Create line-buffer max-line 2 + allot : scan-file ( addr u -- ) begin line-buffer max-line fd-in read-line throw while >r 2dup line-buffer r> compare 0= until else drop then 2drop ;
read-line ( addr u1 fd -- u2 flag ior )
は、 addr からのバッファーに最大 u1
バイトを読み取り、 読み取ったバイト数と、 ファイルの終わりに達した場合に false になるフラグと、 エラーコードを返します。
compare ( addr1 u1 addr2 u2 -- n )
は 2 つの文字列を比較し、 両方の文字列が等しい場合は 0
を返します。 最初の文字列の方が字句的に大きい(lexically greater)場合は正の数値を返し、 2
番目の文字列の方が字句的に大きい(lexically greater)場合は負の数値を返します。
このループは、 まだ見たことがないですよね。 このループは出口が2つあります。 while
はスタック上にある読み取ったバイト数で終了するため、 それを個別にクリーンアップする必要があります。 そのクリーンアップする部分は
else
の後にあります。
使用例:
s" The text I search is here" scan-file
: copy-file ( -- ) begin line-buffer max-line fd-in read-line throw while line-buffer swap fd-out write-line throw repeat drop ;
fd-in close-file throw fd-out close-file throw
これも、同様に、 定義に組み込むことができます:
: close-input ( -- ) fd-in close-file throw ; : close-output ( -- ) fd-out close-file throw ;
研究課題(assignment):
copy-file
を変更して、 2 行目が一致するまでコピーするようにするにはどうすればよいでしょうか? セクションの開始行と終了行を指定して、 テキスト・ファイルのセクションを抽出するプログラムを作成できますか?