Node:Files Tutorial, Next:, Previous:Alignment Tutorial, Up:Tutorial



Files

This section gives a short introduction into how to use files inside Forth. It's broken up into five easy steps:

  1. Opened an ASCII text file for input
  2. Opened a file for output
  3. Read input file until string matched (or some other condition matched)
  4. Wrote some lines from input ( modified or not) to output
  5. Closed the files.

Open file for input


s" foo.in"  r/o open-file throw Value fd-in

Create file for output


s" foo.out" w/o create-file throw Value fd-out

The available file modes are r/o for read-only access, r/w for read-write access, and w/o for write-only access. You could open both files with r/w, too, if you like. All file words return error codes; for most applications, it's best to pass there error codes with throw to the outer error handler.

If you want words for opening and assigning, define them as follows:

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 ;

Usage example:

s" foo.in" open-input
s" foo.out" open-output

Scan file for a particular line


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 ) reads up to u1 bytes into the buffer at addr, and returns the number of bytes read, a flag that is false when the end of file is reached, and an error code.

compare ( addr1 u1 addr2 u2 -- n ) compares two strings and returns zero if both strings are equal. It returns a positive number if the first string is lexically greater, a negative if the second string is lexically greater.

We haven't seen this loop here; it has two exits. Since the while exits with the number of bytes read on the stack, we have to clean up that separately; that's after the else.

Usage example:

s" The text I search is here" scan-file

Copy input to output


: copy-file ( -- )
  begin
      line-buffer max-line fd-in read-line throw
  while
      line-buffer swap fd-out write-file throw
  repeat ;

Close files


fd-in close-file throw
fd-out close-file throw

Likewise, you can put that into definitions, too:

: close-input ( -- )  fd-in close-file throw ;
: close-output ( -- )  fd-out close-file throw ;
Assignment:
How could you modify copy-file so that it copies until a second line is matched? Can you write a program that extracts a section of a text file, given the line that starts and the line that terminates that section?