From Amiga Coding
Jump to: navigation, search

The file.include.ab3 include provides many functions for easily accessing and manipulating files.

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
  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:


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.