In this section, we will learn what is file handling and how it works in C.
Files in C
A music, a video, a picture, a document, etc. each of these sources in our computer is called a file.
A file in its core is nothing but a bunch of binaries arranged together and stored on the hard disk.
One of the most powerful features that a programming language like C brings in to the table is the ability to work with these files.
Using the C programming, we can read the content of a document-file, change the content (add or remove), create a new document from scratch, copy a document and put it in another directory and many other operations that can be done on files.
Of course, these operations are not limited to just a document-file but to pretty much any type of files exist in a computer.
In this section, we introduce the functions that are used to work with files and then in later sections we dive deep into each one of these functions.
C File Functions:
In the table below, you can see the list of file-related functions:
Name | Explanation |
fopen() | Via this function, we set the address of a file in order to open it and make it ready to be read or write depending on the need. |
getc() | When we opened a document-file, via this function we can read its content one character at a time. |
putc() | Via this function, we can put one character at a time to a document-file. |
exit() | This function is not necessarily related to working with files, but is used to end a program if something went wrong. |
fclose() | When we open a file and bring it to a program, it will take some portion of the memory. So it is a good practice to clean that memory space after we’re done with the file and so via this function we can close the file and release the memory space allocated to the file. |
fprintf () | This function is just like the `printf` function, with the exception that it can send the content to a declared file instead of the standard output stream. Basically, it will take the address of an opened file and send any content we put as its argument to that target file. |
fscanf() | Thise function is just like the `scanf` function except it will take its content from a declared file instead of input stream. Basically, it will take the address of an opened file and after that it will read the content of that file and store it in any buffer we declare as its argument. |
rewind() | When we read or write the content of a file and reach to the end or middle of it for example, if we decided for any reason to start again and read from the beginning of the file, we can use this function.
When we call the function and put the address of an opened file as its argument, the next time we attempt to read the file, it will be from the starting point of that file. |
fseek() | Sometimes there’s a file like a document file that we want to read or write on it but not from the starting point! For example, we want to read the content of that file starting from the middle of the file. This is where we can use the `fseek()` function. Via this function, we can change the point from which the read or write to the file should happen. |
ftell() | Sometimes while we’re reading or writing a bunch of content to a file, we want to know the current position of the file. Via this function, we can get the current position of an opened file in a program.
For example, if the program is working on a file and the length of that file is 100 bytes and the program is currently on the byte 40, calling this function will return the number 40. |
fflush() | When writing to a file, usually the content will stay in the memory for quite sometimes and then when that memory location that is allocated for the file is filled with data, the content will be sent to the hard-disk.
But we might want to send the data to the hard-disk where the file is actually stored before the memory gets filled. In such case, we can call this function in order to flush any content in the memory to the hard-disk. |
fgetpos() | The `fgetpos()` function is used to get the current value set for the file-position indicator in the FILE-structure of the target file. |
fsetpos () | Sometimes when we open a file and start to read and write on it, we want to change the current position where the read or write is happening. Via this function we can change the position. |
feof() | When working on a file, it is important to realize when the end of a file is reached. One of the ways to find out is via this function. |
ferror() | Errors can happen, especially when working on files. Via this function we can get errors if they happened when working on an opened file. |
ungetc() | Sometimes when we’re reading the content of a document-file, we might realize the character that has been read is something that shouldn’t be read! Via this function, we can put back that character to the incoming data as if the character wasn’t read at all! So the next time we call to read a character from the same file, we will get that previously read character. |
setvbuf() | When we open a file in a program to work on it, the content of the file before coming to our program is first stored in a memory location called buffer. Likewise, when we want to send data to a file, this data is first stored in a buffer. By default, the size of this memory location is decided by the underlying system. But via this function, we can set a new memory location with any amount of size we’d like. |
fread() | When we have a file that its content is binary (like music file, video file etc.) We can use this function to read its content. |
fwrite() | When we want to send binary content to a file, this is the function that can be used for. |
Alright, in the next couple of sections, we will explain the functions introduced in the table above. But before that let’s run a simple example in order to get a feel of how working with files looks like in the C language:
Example: open a file in C
#include <stdio.h> int main() { //Call the the fopen function in order to open the file in read mode. FILE *file = fopen("G:/r.txt","r"); //if there was a problem on opening the file, exit the program. if (file == NULL){ exit(EXIT_FAILURE); } char c ; //Read the content of the file until the end and send it to the output. while ((c = getc(file)) !=EOF){ printf("%c",c); } //close the file when there's no need of it anymore. fclose(file); return 0; }
Output:
This message is coming from the body of the r.txt
How Does File Handling Work in C?
In the example above, we want to open a file named `r.txt` in the computer and print its content.
The first step in order to read any file is to open it! For this reason, we called the `fopen()` function.
This function takes 2 arguments; the first one is the address of a character-string that defines the location of the target file in the hard-disk. And the second argument is the type of operation that we want to do on the file. In this example, we’re looking for only reading the content of the file and so we used the `r` character, which means `read` operation.
This function returns the address of the memory location that is allocated to the file if it successfully opened the file and a NULL-pointer in case the operation failed. (Like if the directory didn’t exist or the file wasn’t readable, etc.)
Note: this memory contains information about the file that is going to be used. It’s not a pointer to the actual file itself. More on this in fopen() section.
After that we ran an `if-statement` to see if the pointer of type `FILE` is in fact pointing to the file or is it NULL.
If the result of the statement was NULL, the body of the `if` statement will run, which is a call to `exit()` function.
The `exit` function is used to end the program and it takes one argument, which is basically an integer value (0 for successful termination and non-zero otherwise). Here, I’ve used a macro value that says to terminate the program because of a failure.
Note: the value we set for the argument of `exit()` function will be sent to the underlying operating system and it is on the OS to decide what to do with such value.
Moving on to the next line of code in the program, we have the `while` statement and the call to the `getc` function in its condition.
This function takes one argument and that is the memory address of the opened file.
The `getc` function reads one character at a time of the file and returns its result, which we then assigned the character to the `c` variable that is created a line before this `while` loop.
Note: any time we call the `getc` function, it will read the next character of the opened file.
The loop will continue until the `getc` function reach to the end of the file and in that case the return value of this function will be equal to `EOF` which means `End-of-File`.
In that case, the loop will break, and the instructions after the loop will run.
Note: within the body of this loop, the program simply printed each character it got from the file.
In the last line of this program, there’s a call to the `fclose` function. The call to this function is because we want to de-allocate and release the memory space allocated to the file.
The function takes one argument, and that is the memory address of the file that we want to close.