In this tutorial, we are going to learn about reading and writing files in C.
File Handling in C:
The English dictionary term file refers to a folder or a box used for storing loose papers together (mostly in order) for easy reference.
However, in computer terminology, a file is a collection of related data stored as a unit with a name to identify it.
There can be different types of files like text files, image files, music files, videos etc. In all these files, the data is finally stored as bits (bytes).
Until now, we have been using functions like scanf(), printf(), gets(), puts(), etc., to read and write data from the console (terminal) in a program.
During execution, such programs read data, process or transform the data, and finally print the result to the console. However, in a real-life scenario, programs often store data, so that it can be read or retrieved later by some other program.
The C programming language provides an interface called stream to read and write to files.
A stream can also be used to read and write to other devices (peripherals) like – storage disks, network interfaces, printers, etc.
It is for this reason a stream is considered as a source or a destination for data.
Before using a stream to read or write, we need to perform the open operation. In the end, when the job is done, we need to perform a close operation.
The open operation will establish a connection with the file and the close operation will disconnect from the file.
The data stored in files can be accessed in two ways:
- Sequential Access: the data is read or retrieved in a sequential manner starting from the beginning to the end in order. Here, one cannot directly jump to a specific location or skip to the end.
- Random Access: the data present at a particular location can be directly accessed using its offset from the beginning of the file.
There are four basic file operations:
- Opening a file
- Reading data from a file
- Writing data to a file
- Closing a file
A file has to be opened before performing any operation on it. On opening a file, the operating system (OS) provides a handle to perform various file operations using different functions.
A request made to the operating system (OS) for opening a file can either succeed or fail.
If the request succeeds, the operating system returns a file descriptor (handle) which is a pointer to the structure FILE. If the request fails, a null pointer (NULL) is returned.
A file can be opened by using fopen(). This function returns the file descriptor as FILE pointer.
The declaration of fopen() as available in stdio.h is:
FILE *fopen(char *filename, char *mode);
- the filename is a sequence of characters that make up a valid filename on the given operating system and,
- the mode determines the way in which the opened file will be used (i.e, for reading, writing or appending, etc..). It also allows us to read or write data either in text or binary format.
Note: The filename can also include the complete path of the file.
fig 1. Different modes for text files
fig 2. Different modes for binary files
The data structure of a file descriptor is defined as FILE in the standard library stdio.h. Hence, all files are declared as type FILE before they are used.
Consider an example:
FILE *fp; //fp is a FILE pointer variable that represents the file descriptor fp = fopen("Hello.txt", "w"); //fopen() function opens a file "Hello.txt" in writing mode
Note the difference in the fopen() operation in the different modes:
- When the mode is write-only, a file with a specified name is created if the file does not exist and the contents are deleted if the file already exists.
- When the mode is read-only, the file is opened with the current contents, if the file already exists, else an
- When the mode is appended, the file is opened with the current contents of the file exist, else a new file with the given name and path is created.
The file that is opened by using fopen() should be closed after the work is over on that file. A file close will flush out all the entries from the buffer.
Files are closed with the function fclose(). By closing a file after operations performed on that file will save all the modifications done on the file.
The general syntax of fclose() is:
int fclose(FILE *fp);
The fclose() function closes the file that is being pointed by file pointer fp.
An important point regarding fclose() is closing a file will prevent misuse of the FILE.
If an error occurs in closing a file then fclose() returns EOF (End Of File). For successful close operation, it returns 0.
Lets consider an example:
FILE *fp; fp = fopen("sample.txt", "r"); ........... // perform operations on file fclose(fp); // disassociate the file with the stream
Read and Write mixed data values using fread() and fwrite()
For example consider the integer value 15679 which occupies 2 bytes of memory but when it is transferred to the disk file using fprintf() function it would occupy 5 bytes of memory. For each character one byte would be required.
Even for float each digit including dot (.) requires one byte. Thus, large amount of integers or float data requires large space on the disk.
Hence in the text mode storing of numerical data on the disk turns out to be inefficient. To overcome this problem the files should be read & written in binary mode, using the functions fread() & fwrite().
The fwrite() function is used for writing a structure block onto a given file.
The syntax is:
fwrite(&structure_variable, sizeof(structure), integer, file_pointer);
In the above syntax the first argument is the address of the structure to be written onto the disk, the second argument is the size of the structure in bytes, the third argument is the number of such structures (records) that the user wants to write at one time and the last argument is the file pointer.
The fread() function is used for reading an entire structure block from a given file.
The syntax is:
fread (&structure_variable, sizeof(structure), integer, file_pointer);
Happy Learning 🙂