# 9. Files and disk There is no 1541. The disk verbs work against the filesystem where that means something, and refuse by name where it does not. ## Program storage ```basic repl 10 PRINT "HI" DSAVE "myprogram.bas" DLOAD "myprogram.bas" VERIFY "myprogram.bas" ``` ```output OK ``` `SAVE` and `LOAD` are the same verbs under their other names, and `DVERIFY` is `VERIFY`. A program is saved as plain text with its line numbers, so you can edit it in anything. `VERIFY` compares what is in memory against the file and prints `OK`, or reports how many lines differ. ## Files Ten channels, numbered 0 to 9. ```basic 10 DOPEN 1, "scores.txt", W 20 PRINT #1, "ADA 4000" 30 PRINT #1, "GRACE 3800" 40 DCLOSE 1 50 DOPEN 2, "scores.txt" 60 INPUT #2, LINE$ 70 PRINT LINE$ 80 DCLOSE 2 ``` ```output ADA 4000 ``` | Verb | What it does | |---|---| | `DOPEN n, "name"` | open for reading | | `DOPEN n, "name", W` | open for writing | | `APPEND n, "name"` | open for writing at the end | | `DCLOSE n` | close one channel | | `DCLOSE` | close all of them | | `PRINT #n, expr` | write a line | | `INPUT #n, VAR` | read a line | | `RECORD n, r` | position at record `r` | **Note the space before the `#`.** A C128 writes `PRINT#1,A$`; here the `#` has to be its own word, because `PRINT#` would otherwise scan as a variable name. See Chapter 13. Reading past the end of a file leaves the variable empty rather than raising, so a read loop tests what it got: ```basic setup=textfiles 10 DOPEN 1, "data.txt" 20 DO 30 INPUT #1, L$ 40 IF L$ = "" THEN EXIT 50 PRINT L$ 60 LOOP 70 DCLOSE 1 ``` ```output ONE TWO ``` Reading a channel opened for writing — or writing one opened for reading — is refused, as is using a channel that is not open. `RECORD` counts *lines*, not fixed-length records: a filesystem file has no record length to seek by, so it rewinds and reads forward. ## Managing files ```basic setup=textfiles 10 COPY "a.txt", "b.txt" 20 CONCAT "a.txt", "b.txt" 30 RENAME "b.txt", "c.txt" 40 SCRATCH "c.txt" ``` `COPY` duplicates, `CONCAT` appends one file to another, `RENAME` moves, `SCRATCH` deletes. Deleting a file that is not there is reported rather than ignored. ## Binary blocks ```basic 10 A$ = "BINARY DATA" 20 B$ = "............" 30 BSAVE "block.dat", POINTER(A$), POINTER(A$) + 12 40 BLOAD "block.dat", POINTER(B$), 12 50 PRINT B$ ``` ```output BINARY DATA ``` `BSAVE` writes a range of memory and `BLOAD` reads one back. **`BLOAD` requires a length**, unlike a C128's, because the address is a real address in this process and a file longer than you expected would write past whatever you pointed at. For the same reason line 20 is not optional: `POINTER` gives you the address of a string that already exists, and reading into one you never sized writes over something else. ## What is refused, and why | Verb | Why not | |---|---| | `HEADER` | formats a disk. On a filesystem that would have to mean "delete everything here" | | `COLLECT` | validates a disk's block allocation map. There is no map | | `BACKUP` | duplicates one disk onto another. There are no disks | | `BOOT` | loads and runs a boot sector. There is no boot sector | | `DIRECTORY` / `CATALOG` | needs a directory-reading wrapper the standard library does not have yet. Filed upstream | `DCLEAR` is the exception among the drive verbs: resetting a drive also closes its channels, and closing the channels is real, so that is what it does. Each refusal names itself and says why: ```basic 10 HEADER "DISK" ``` ```output ? 10 : RUNTIME ERROR HEADER formats a disk, and there is no disk drive here -- only a filesystem ```