Relative File Mechanics
Jim Butterfield, Toronto
I'll use the Basic 4.0 commands, since they are more convenient.
Creating a Relative File
To create a new Relative file, we may use Direct Commands if we wish. This is the easiest way to see how it all happens — try it Directly and later you can incorporate it into a program if you wish. Suppose we want a file of 25 items (initially) each of which may be up to 20 characters long.
DOPEN#1, "RFILE",L20 opens the file for relative writing. We've specified a length of 20 characters.
RECORD#1, 25 positions us to the last record desired, number 25, but this doesn't exist yet. The error light on the disk will turn on; we find a RECORD NOT PRESENT signalled. If we tried INPUT or GET at this time, we'd be in serious trouble. But we can still write, and this will create all records up to and including number 25.
PRINT#1 writes a Return character in record 25 of the file, and incidentally creates all records up to and including 25. You'll notice a delay of several seconds while this happens.
DCLOSE#1 wraps up the file in the usual way.
Writing to a relative file
If you have gone through the DOPEN/RECORD/PRINT/DCLOSE sequence above, we can use this file to write some data. Once again, let's use Direct statements to allow us to watch things happening.
DOPEN#1, "RFILE" opens our file for reading or writing. Note that we don't need to specify the file type (REL) or whether we wish to read or write (we might do either). And we must not specify the length L — that's only for creating the file.
RECORD#1, 10 positions us so that we can read or write record number 10. There's no error light this time, since record 10 is in place. Note that if our record number was a variable such as X, we'd need to put it in brackets, e.g., RECORD#1,(X). Now let's write a few records starting at item ten.
PRINT#1, "HELLO" writes six characters (HELLO plus the RETURN character) to record number 10; the disk automatically positions to the start of record 11. This positioning is not triggered by the Return character — it's done by recognizing the end of PET's transmission (technically speaking, the EOI line).
PRINT#1, "THERE"; uses a semicolon to supress Return so only five characters are written to record 11. End of transmission is correctly detected, however, and the disk positions to record 12. PRINT#1, "A" + 7CHR$(13) + "B" writes a single record, even though there are two Returns. When we are reading, it will take two INPUT# statements to get the information, since INPUT stops on a Return character.
PRINT#1, "THIR" + "TEEN" writes THIRTEEN in the usual way. PRINT#1, "FOUR"; "TEEN" writes FOURTEEN.
PRINT#1, "MORE THAN TWENTY CHARACTERS" will generate a disk error, "Overflow in Record", which tells you that you're trying to fit too much into a record. The first twenty characters will be written to the record, the rest discarded.
DCLOSE#1 terminates our writing session.
Reading from a relative file
We must have a program to GET# or INPUT# our data; these commands can't be given as Direct statements.
100 DOPEN#1, "RFILE" 110 INPUT "RECORD NUMBER DESIRED" ; R 120 IF R = 0 GOTO 190 130 RECORD#1, (R) 140 IF DS > 0 THEN PRINT DS$ : GOTO 110 150 INPUT#1, R$ 160 PRINT R$ 170 IF ST = 0 GOTO 150 180 GOTO 110 190 DCLOSE#1
Use the above program to browse through the items we have just written. You'll find some interesting things. For example, what do you see in records you have never written (say, record 4)? What happens if you try for record number 200? Does it seem to matter if you have written a Return to the record or not?
A new role for ST, the Status Byte
About the ST test in line 170: you may recall that we created a record with more than one item. Record 12 had two items (called "fields") each followed by a Return character. An INPUT# statement will stop on the first Return and would not see the second field.
But ST works in a very useful way: it is set to 64 (end of file) at the end of every record. That means that if we might have more than one field in a record, we can check ST to see if we have read the last one.
One drawback of this mechanism is that you can't use ST to tell you if you are at the end of a relative file; it flags EOF after every record. How do you tell when you're at the end? Use the RECORD command; when you get an error 50, RECORD NOT PRESENT, you'll know you are past the end.
Enlarging a file
Easy. Use RECORD followed by PRINT# in the same manner as when you created the file. The new records will automatically be written up to the record number you have specified.
Conclusion
There are new rules to learn. But Relative files are easy to use, and add power and speed to your programs.