An article aimed at programmers who need to use file handling in C, helping to promote good practice, offer some standard solutions, and avoid pitfalls.
The purpose of this article is to cover, from a high level, the various aspects of file handling in C that programmers should be aware of. These tips might be useful for every software developer, even if you are engaged in augmented software development for professional company. We shall look at:
- types of file;
- how to open and close files;
- how to read from and write to files;
- ways to check the size and test for the end of file.
- Along the way, we shall point out any potential pitfalls and programming best practices.
Types of File Handling in C
There are two key kinds of file that programmers need to know how to deal with:
- sequential - one byte (or block of bytes) at a time;
- random access - accessed using some kind of index, in no particular order.A file can actually be split into two parts - a sequentially accessed index (list of records) and random access part (the record data) which is designed to provide faster access than just reading and discarding records when trying to find the item being requested.
Most files that programmers come across tend to be sequential. They can have one of two formats:
- text - readable text, possibly interpreted by the operating system, i.e. ASCII vs. EBCDIC;
- binary - pure data with no representation i.e. byte (numeric) values.
Either of these file types can be accessed sequentially or using random access, and the type of file is specified at the time it is opened.
Opening and Closing Files
A file is opened using the fopen function, and if it doesn't exist, can be created with the fopen function set to write to the file. To avoid overwriting an existing file, it is necessary to attempt to open it as read-only, and if it doesn't, open it as a writable file.
Caution: if an existing file is opened as writable, it will be truncated; to append to a file, the append flag can be used instead.
All variations of fopen return a file pointer (defined as FILE *) which can be tested against NULL, with a NULL value indicating that the file does not exist.
This file pointer is needed to subsequently close the file.
Determining the File Size
To find out the size, without moving the file pointer, it is necessary to:
- store the current file position;
- fast forward to the end of the file;
- note the position;
- rewind to the previous position in the file.
This is illustrated in the article Writing a File Size Function. Note that to find out if the end of the file has been reached, the fread function return value can be tested against the constant EOF.
Reading and Writing From Files in C
Data can be read from the file byte by byte using the getc function, which returns an (interpreted) character value. The companion function putc writes a text character to the file.
Formatted data can also be processed using fprintf and fscanf, which work in the same way as the stdio.h functions printf and scanf. These functions are only usable with a text file.
Binary files are processed using fread and fwrite. These functions operate on memory that has been allocated using malloc, and cast to a usable data type.
Before using any of these functions, a valid file pointer must have been obtained, otherwise the results are undefined, sometimes ending in a crash.