Every program covered so far in this series has shared one limitation: the moment the program finishes running, all of its data disappears completely. Variables, arrays, and even dynamically allocated memory are wiped clean the instant the program ends, leaving nothing behind for the next time the program runs. File handling is what solves this problem, allowing a program to save data permanently to disk, and later read that same data back, even after the program has been closed and reopened many times.
Almost every meaningful piece of software you use daily relies on file handling in some form, whether it is saving a document, storing application settings, or logging data for later analysis. In C, file handling is managed through a consistent set of functions built around a special data type that represents an open file.
In this tutorial, you will learn how to open and close files, the different file modes available for reading, writing, and appending data, how to write formatted data and plain text to a file, how to read that data back, and some of the most common mistakes beginners encounter when working with files in C.
File handling refers to the process of creating, opening, reading from, writing to, and closing files using program code, rather than relying on data that only exists temporarily while a program is running. In C, files are represented using a special pointer type that keeps track of the current position and status of an open file.
#include <stdio.h>
int main() {
FILE *filePointer;
filePointer = fopen("channelinfo.txt", "w");
if (filePointer == NULL) {
printf("Could not open the file.");
return 1;
}
fprintf(filePointer, "CS Engineering Gyan");
fclose(filePointer);
printf("File written successfully.");
return 0;
}
File written successfully.
This short example already demonstrates the basic pattern behind almost every file operation in C: opening a file, checking whether it opened successfully, performing an operation on it, and finally closing it once the work is complete.
The fopen function opens a file and returns a pointer that is used for all further operations on that file. It requires two pieces of information: the name of the file to open, and the mode describing how the file should be used.
FILE *filePointer = fopen("filename", "mode");
| Mode | Description |
|---|---|
| "r" | Opens a file for reading; the file must already exist. |
| "w" | Opens a file for writing, creating it if it does not exist, and erasing its existing contents if it does. |
| "a" | Opens a file for appending, adding new data to the end without erasing existing content. |
| "r+" | Opens a file for both reading and writing; the file must already exist. |
Since a file might fail to open for reasons such as a missing file or insufficient permissions, it is important to check whether fopen returned a valid pointer before attempting to use it further.
#include <stdio.h>
int main() {
FILE *filePointer;
filePointer = fopen("subscribers.txt", "r");
if (filePointer == NULL) {
printf("File could not be opened. It may not exist.");
return 1;
}
printf("File opened successfully.");
fclose(filePointer);
return 0;
}
Attempting to use a NULL file pointer for reading or writing would lead to undefined behavior, which is exactly why this check should be performed immediately after every call to fopen.
The fprintf function writes formatted data to a file, working almost identically to printf, except that the output is directed to a file instead of being displayed on the screen.
#include <stdio.h>
int main() {
FILE *filePointer;
filePointer = fopen("videostats.txt", "w");
int views = 4300;
float rating = 4.7;
fprintf(filePointer, "Views: %d, Rating: %.1f", views, rating);
fclose(filePointer);
printf("Data written to file.");
return 0;
}
Data written to file.
After running this program, a file named videostats.txt would contain the formatted text produced by fprintf, saved permanently until it is opened, modified, or deleted again in the future.
When only plain, unformatted text needs to be written to a file, the fputs function offers a simpler alternative to fprintf, writing an entire string to the file exactly as provided.
#include <stdio.h>
int main() {
FILE *filePointer;
filePointer = fopen("welcome.txt", "w");
fputs("Welcome to CS Engineering Gyan!", filePointer);
fclose(filePointer);
printf("Message saved to file.");
return 0;
}
Message saved to file.
The fscanf function reads formatted data from a file, mirroring the behavior of scanf, but pulling its input from a file rather than from the keyboard.
#include <stdio.h>
int main() {
FILE *filePointer;
int views;
filePointer = fopen("views.txt", "r");
fscanf(filePointer, "%d", &views);
printf("Views read from file: %d", views);
fclose(filePointer);
return 0;
}
Views read from file: 4300
This example assumes that views.txt already contains a numeric value saved by an earlier program, demonstrating how data can be passed between separate program runs through a file rather than being lost when each run ends.
Just as fgets is useful for reading a full line of user input that may contain spaces, it works equally well for reading an entire line of text directly from a file.
#include <stdio.h>
int main() {
FILE *filePointer;
char line[100];
filePointer = fopen("welcome.txt", "r");
fgets(line, 100, filePointer);
printf("Content read: %s", line);
fclose(filePointer);
return 0;
}
Content read: Welcome to CS Engineering Gyan!
When new data needs to be added to a file without removing what is already stored there, the append mode allows writing to begin at the end of the existing content, rather than overwriting it from the very start.
#include <stdio.h>
int main() {
FILE *filePointer;
filePointer = fopen("log.txt", "a");
fprintf(filePointer, "New tutorial published today.\n");
fclose(filePointer);
printf("Log entry added.");
return 0;
}
Log entry added.
Running this program multiple times would continue adding new lines to the end of log.txt each time, rather than erasing the previous entries the way write mode would.
A common pattern when working with files involves reading every line until the end of the file is reached, which can be accomplished by repeatedly calling fgets inside a loop until it fails to read any further content.
#include <stdio.h>
int main() {
FILE *filePointer;
char line[100];
filePointer = fopen("log.txt", "r");
while (fgets(line, 100, filePointer) != NULL) {
printf("%s", line);
}
fclose(filePointer);
return 0;
}
New tutorial published today.
The loop continues calling fgets until it returns NULL, which happens once the end of the file has been reached, at which point there is no more content left to read.
Every file opened using fopen should eventually be closed using fclose, which ensures that any data still waiting to be written is properly saved, and that the resources associated with the open file are released back to the operating system.
| Reason to Close a File | Explanation |
|---|---|
| Data Integrity | Ensures that any buffered data is fully written to the file before the program continues or ends. |
| Resource Management | Releases system resources associated with the open file, which is especially important in programs handling many files. |
| Preventing Corruption | Reduces the risk of leaving a file in an inconsistent or incomplete state. |
| Mistake | Correct Practice |
|---|---|
| Forgetting to check whether fopen returned NULL. | Always verify that the file pointer is not NULL before performing any read or write operations. |
| Using write mode when append mode was actually intended. | Use append mode whenever existing content in a file needs to be preserved rather than overwritten. |
| Forgetting to close a file after finishing operations on it. | Always call fclose once all necessary reading or writing has been completed. |
| Assuming a file will always exist when opening it in read mode. | Handle the possibility that the file does not exist by checking the returned pointer before proceeding. |
File handling extends the lifespan of a program's data far beyond a single execution, allowing information to be saved permanently to disk and read back again whenever it is needed. By understanding how to open files with the correct mode, write both formatted and plain text data, read that data back using fscanf and fgets, and properly close files once finished, you gain the ability to build programs that genuinely persist information over time.
In this tutorial, you learned what file handling involves, how to open and close files safely, the different file modes available for reading, writing, and appending, and how to perform common file operations while avoiding pitfalls such as forgetting to check for a NULL file pointer or unintentionally overwriting existing data. With file handling covered, you now have a solid, complete foundation across the core concepts of C programming, from basic syntax all the way through pointers, structures, dynamic memory, and persistent file storage.