Blitz:File.include.ab3
The file.include.ab3 include provides many functions for easily accessing and manipulating files.
Contents
Opening and Closing Files
Opening Files
Files must be opened before they can be read from or written to. This is normally done using the file_Open{} function. Two arguments are required, the name of the file as a string, which can include a full or relative path also if required, and the mode in which to open the file. The mode should be one of the following constants:
Constant | Mode Description | Exclusive? |
---|---|---|
#file_read | Opens file for reading and writing if it exists, fails if the file doesn't exist. Use this for reading files. | No |
#file_open | Opens the file for reading and writing if it exists, or creates a new empty file if the given filename doesn't exist. Use this for modifying existing files. | No |
#file_write | Opens the file for writing. If it already exists, a requester will open asking whether to overwrite the existing file or cancel. If the user cancels, the function will return a failure (-1). | Yes |
#file_forcewrite | As for #file_write, except it does not ask permission before overwriting the file. Use this along with the dos_Exist{} function from dos.include.ab3 if you would prefer to handle your own "Are you sure?" requesters, or don't need to check (e.g. saving config files). | Yes |
The function returns a (long) File ID number if successful, or -1 if it fails for any reason. This File ID is used by other procedures in file.include.ab3 so you need to store it for later use. Note that the File ID could be 0, so ensure you take this into account when you check for success:
fid.l = file_Open{"Ram:Test.txt", #file_read} If fid >= 0 ; Do all your file reading here and close the file again Else NPrint "Unable to open file for reading!" End If
Reasons file_Open{} could fail include:
- Trying to read a file that doesn't exist
- Trying to read a file that is read protected (i.e. doesn't have the r flag set)
- Trying to write to a file that is write protected (i.e. doesn't have the w flag set)
- Trying to write to a file that is on a read-only volume (e.g. a CD-ROM or write-protected floppy)
- Trying to create a file with the same name as a directory in the same path
It is very important not to access a file that you haven't successfully opened! Always check for success and make sure your file access code will only be executed if you successfully open the file.
Closing Files
Closing files that were previously opened is simple using the file_Close{} statement. The only argument it requires is the File ID from the file_Open{} function of the file you want to close:
file_Close{fid}
It is important to close files when you're finished as sometimes the information written to the file might only be in the filesystem's cache, and will only actually saved when the file is closed. This can lose the information saved, and with the Fast File System it can be especially dangerous if the Amiga is powered off, crashes or resets while files are held open. Closing files also frees the file for access by other programs should they need it.
Reading and Writing
Once a file is successfully opened, you're ready to read and write information. This can be done in a number of ways, depending on your needs.
Reading and Writing Text
Lines of text are very simple to read and write with the file_ReadLine{} and file_WriteLine{} functions. Both require the File ID of a currently open file. the file_ReadLine{} function returns a string containing the next line to be read in the file, up to either the next line break or the end of the file, whichever comes first:
myline$ = file_ReadLine{fid} NPrint "Line read: ", myline$
The file_WriteLine{} function writes the given string to the file, returning True (-1) if successful or False (0) if not:
succ = file_WriteLine{fid, "Line of Text!"} If succ = False Then NPrint "Error writing to file!"
Reading and Writing Binary
In a similar way, individual byte, word, longword and float values can be read and written easily. The functions used for these operations are:
Value Type | Read | Write |
---|---|---|
Byte (8 bits) | value.b = file_ReadByte{fid} | succ = file_WriteByte{fid, value.b} |
Word (16 bits) | value.w = file_ReadWord{fid} | succ = file_WriteWord{fid, value.w} |
Longword (32 bits) | value.l = file_ReadLong{fid} | succ = file_WriteLong{fid, value.l} |
Float (32 bits) | value.f = file_ReadFloat{fid} | succ = file_WriteFloat{fid, value.f} |
Naturally, the value being read or written needs to match the type of value being read or written. All write operations will return a true if the operation is successful, false otherwise. After each operation, the current position in the file will be updated appropriately, so the next read or write operation takes place directly after the last. No separating or end-of-line (EOL) characters are inserted following each write, so multiple values written follow each other directly. This means you need to know the expected layout of your data in advance.
Reading and writing chunks of binary directly to or from RAM is also possible using the file_ReadMem{} and file_WriteMem{} calls:
succ = file_ReadMem{fid, memaddr.l, numbytes.l} succ = file_WriteMem{fid, memaddr.l, numbytes.l}
Unlike the other reading and writing functions, you have to be really careful with these ones! They read and write directly from or to whatever memory address you tell them, without checking if this is a valid or safe thing to do. You can instantly crash your machine, corrupt files and so on very easily by providing the wrong values!
Unlike the previous reading functions, the data read is transferred directly to the memory address given and only a success or fail flag is returned by the function. The numbytes parameter is the number of consecutive bytes to be read or written. This can be used to efficiently load or save large blocks of data, e.g. custom image formats, maps etc. that aren't stored in a more common or readable format. With careful use, they can even be used to load or save the contents of large arrays without looping through every element.