Quick Reference
File Pointers
Functions to handle files come from the stdio library. We need to include the stdio.h header file if we wish to use those functions:
To use files we need to have variables that act as handles to files we are interested in. These are file pointer variables. fp is a file pointer variable.
FILE* fp;
Opening Files with fopen()
To work with a file, you must first open it using the fopen() function. The fopen() function takes two arguments:
- The filename (a string representing the path to the file)
- The mode (a string indicating how the file should be opened)
The function returns a FILE pointer if successful, or NULL if the file cannot be opened.
FILE *fp = fopen("filename.txt", "r");
File Access Modes
The mode parameter determines how the file will be accessed. Here are the most common modes:
| Mode | Meaning | Description |
|---|---|---|
"r" | Read | Opens an existing file for reading. The file must exist. |
"w" | Write | Opens a file for writing. If the file exists, it is truncated (emptied). If it does not exist, a new file is created. |
"a" | Append | Opens a file for writing at the end. If the file exists, new data is added to the end. If it does not exist, a new file is created. |
Error Checking
It is really important to check whether fopen() was successful before attempting to use the file pointer. If the file cannot be opened, fopen() returns NULL. Attempting to use a NULL file pointer will cause your program to crash.
FILE *fp = fopen("data.txt", "r");
if (fp == NULL) {
printf("Error: Could not open file.\n");
return 1; // Exit the program with an error code
}
This pattern of checking for NULL should become automatic whenever you open a file.
Reading from Files
Once a file is open for reading, you can read data from it using several functions. The choice of function depends on what you want to read.
Reading Lines with fgets()
The fgets() function reads an entire line from a file (up to a specified number of characters) and stores it in a string.
FILE* fp = fopen("somefile.txt", "r");
char line[100];
if (fgets(line, 100, fp) != NULL) {
printf("Read line: %s", line);
}
The fgets() function takes three arguments:
- A character array (string) where the line will be stored
- The capacity of the character array you are reading into
- The file pointer associated with the file being read
Note that fgets() includes the newline character (\n) in the string if one is present. If we wan't to get rid of the terminal \n we will need to add a null character where the terminal \n is located
Reading Formatted Data with fscanf()
The fscanf() function works similarly to scanf(), but reads from a file instead of standard input. It is useful for reading structured data.
FILE* fp = fopen("somefile.txt", "r");
int age;
char name[50];
fscanf(fp, "%s %d", name, &age);
The above format string will read a string (without spaces), a space and a number from the file somefile.txt
Writing to Files
Once a file is open for writing or appending, it can be written to. While there are a number of functions that will allow you to write to a file, one of the most familiar function to work with is fprintf().
Writing Formatted Data with fprintf()
The fprintf() function works like printf(), but writes to a file instead of the screen.
FILE* fp = fopen("somefile.txt", "w");
int age = 25;
char name[15] = "Allison";
fprintf(fp, "Name: %s, Age: %d\n", name, age);
Closing Files with fclose()
When you are finished working with a file, you must close it using the fclose() function. Closing a file:
- Flushes any buffered data to the file
- Frees up system resources
- Prevents accidental further access to the file
fclose(fp);
It is good practice to check the return value of fclose(), though this is less critical than checking fopen().
if (fclose(fp) != 0) {
printf("Warning: Error closing file.\n");
}
Failing to close files can lead to data loss (buffered data may not be written to disk) and resource leaks (the operating system may limit the number of open files).
This program:
- Opens
output.txtfor writing - Prompts the user for their name and age
- Writes the data to the file using
fprintf() - Closes the file
- Confirms to the user that the data was written
Example: Appending to a File
The following program appends data to an existing file rather than overwriting it.
#include <stdio.h>
int main(void)
{
FILE *fp;
char entry[100];
// Open the file for appending
fp = fopen("log.txt", "a");
if (fp == NULL) {
printf("Error: Could not open log.txt\n");
return 1;
}
// Prompt user for entry
printf("Enter a log entry: ");
fgets(entry, sizeof(entry), stdin);
// Append to file
fprintf(fp, "%s", entry);
// Close the file
fclose(fp);
printf("Entry added to log.txt\n");
return 0;
}
Notice that we use mode "a" to append rather than "w" to write. This preserves existing content in the file.
Common File I/O Patterns
Pattern 1: Read Entire File Line by Line
FILE *fp = fopen("file.txt", "r");
if (fp == NULL) {
printf("Error opening file\n");
return 1;
}
char line[256];
while (fgets(line, sizeof(line), fp) != NULL) {
// Process line
printf("%s", line);
}
fclose(fp);
Pattern 2: Read Entire File Character by Character
FILE *fp = fopen("file.txt", "r");
if (fp == NULL) {
printf("Error opening file\n");
return 1;
}
int ch;
while ((ch = fgetc(fp)) != EOF) {
// Process character
printf("%c", (char)ch);
}
fclose(fp);
Pattern 3: Read Structured Data
FILE *fp = fopen("data.txt", "r");
if (fp == NULL) {
printf("Error opening file\n");
return 1;
}
int id;
char name[50];
while (fscanf(fp, "%d %s", &id, name) == 2) {
// Process record
printf("ID: %d, Name: %s\n", id, name);
}
fclose(fp);
Detecting End-of-File
There are several ways to detect when you have reached the end of a file:
fgets()returnsNULLfscanf()returns fewer items than expected
It is important to use the appropriate method for the function you are using. Alternatively, you can also use the feof() function. This function indicates whether or not a preceding input operation encountered an end of file character.
if (feof(fp)){
printf("this will print if the previous file input operation encountered the end of file marker");
}