Skip to main content

Someone wanted to learn this too, so Grasp built them a personal learning path.

You can keep exploring this one or create your own

File I/O with fopen, fscanf, fprintf, and fclose

Hello! In our last session, we built programs that could receive and process input directly from the command line. While powerful, that data is transient—it disappears once the program finishes. Today, we'll learn how to make our data persistent by storing it in files.

This lesson addresses the core of file handling in C. We will explore how to open a text file for reading or writing, use functions to transfer data between your program and the file, and properly close the file to ensure your data is saved correctly. You will learn to use the essential functions fopen, fprintf, fscanf, and fclose.

1. The File I/O Lifecycle: Pointers, Opening, and Closing

Before we can read from or write to a file, our program needs to establish a connection to it. In C, this connection is managed through a special pointer variable of type FILE. Think of this FILE pointer as a "handle" that your program uses to refer to a specific open file.

The three fundamental steps for any file operation are:

  1. Open the file using fopen(), which returns a FILE pointer.
  2. Perform read or write operations using functions like fprintf or fscanf.
  3. Close the file using fclose() to save changes and release the handle.

Let's start by understanding the fopen() function. It takes two arguments: a string for the file's path and a string for the "mode," which specifies what you intend to do with the file.

Programiz C Files I/O: Opening, Reading, Writing and Closing a file

This reading from Programiz introduces the FILE pointer and the fopen() function, providing a clear table of the different opening modes.

Start at the section "Working with files" and read down to and including the table under "Opening Modes in Standard I/O". Pay close attention to the modes r (read), w (write), and a (append), as these are the most common modes for text files.

As you saw, opening a file in "w" mode will create it if it doesn't exist, but it will erase all content if it does. In contrast, "a" mode also creates the file if needed but adds new data to the end, preserving existing content. The "r" mode is strictly for reading and will fail if the file doesn't exist.

Every file you open must be closed. The fclose() function takes the FILE pointer as its argument. Closing a file is crucial because it flushes any data that might be waiting in a buffer to be written to the disk and frees up system resources.

2. Writing to a Text File with fprintf()

Once you have a file open for writing (using mode "w" or "a"), you can write formatted data to it using fprintf(). This function works almost exactly like printf(), with one key difference: its first argument is the FILE pointer indicating where to write the output.

Let's look at a complete example that writes a user's input to a file.




#include <stdio.h>
#include <stdlib.h> // for exit()

int main() {
    int age;
    char name[50];
    FILE *file_pointer;

    // Open "log.txt" in append mode.
    // New data will be added to the end of the file.
    file_pointer = fopen("log.txt", "a");

    // It's good practice to check if the file opened successfully.
    // fopen() returns NULL on failure. We will cover this more in the next lesson.
    if (file_pointer == NULL) {
        printf("Error: Could not open file.\n");
        return 1; // Exit with an error code
    }

    // Get input from the user
    printf("Enter your name: ");
    scanf("%s", name);
    printf("Enter your age: ");
    scanf("%d", &age);

    // Write formatted output to the file
    fprintf(file_pointer, "Name: %s, Age: %d\n", name, age);

    // Close the file to save the changes
    fclose(file_pointer);

    printf("Data successfully appended to log.txt\n");

    return 0;
}

Compile and run this program a few times. You'll see that each time, a new line is added to log.txt, demonstrating the append mode. If you change "a" to "w", you'll find that log.txt is overwritten with only the latest entry each time.

3. Reading from a Text File with fscanf()

To read data from a file, you open it in read mode ("r") and use fscanf(). Similar to scanf(), fscanf() reads data from a source and interprets it according to a format string. The first argument is the FILE pointer from which to read.

A common task is to read all the data in a file until you reach the end. fscanf() is perfect for this. It returns a special value, EOF (End of File), when it tries to read but there's no more data left. We can use this to control a loop.

The following video provides an excellent walkthrough of writing and, more importantly, reading data using a while loop that continues until EOF is reached.

File Access Basics | C Programming Tutorial

This video from Portfolio Courses demonstrates the fundamental read/write operations and introduces the crucial concept of looping until the end of a file.

Watch from the beginning to understand file handles and opening a file for writing: File handles. Continue watching to see fprintf and the difference between write ('w') and append ('a') modes: Writing and appending. Finally, focus on how to read data back using fscanf in a loop that checks for EOF: Reading with fscanf.

As the video demonstrated, the while (fscanf(...) != EOF) pattern is a cornerstone of file processing in C. Let's see it in a focused example. Imagine you have a file named data.txt with the following content:

10
25
-5

The following program will read each number, add it to a sum, and count how many numbers were read.




#include <stdio.h>
#include <stdlib.h>

int main() {
    int value;
    int sum = 0;
    int count = 0;
    FILE *file_pointer;

    // Open data.txt in read mode
    file_pointer = fopen("data.txt", "r");

    if (file_pointer == NULL) {
        printf("Error: Could not open data.txt for reading.\n");
        return 1;
    }

    // Loop as long as fscanf can successfully read an integer.
    // fscanf returns EOF when it reaches the end of the file.
    while (fscanf(file_pointer, "%d", &value) != EOF) {
        sum += value;
        count++;
        printf("Read value: %d\n", value);
    }

    // Close the file
    fclose(file_pointer);

    if (count > 0) {
        printf("\nFinished reading file.\n");
        printf("Sum of %d numbers is: %d\n", count, sum);
        printf("Average: %.2f\n", (double)sum / count);
    } else {
        printf("No numbers were found in the file.\n");
    }

    return 0;
}

Before running this, make sure to create the data.txt file with some numbers in it. This example combines file input with the looping and calculation logic you've already mastered.

4. Practical Exercise

To solidify your understanding, let's complete a short exercise.

Task:

  1. Create a program named writer.c. This program should use a for loop to ask the user to enter 3 numbers. It should write each number on a new line in a file called numbers.txt. Important: The file should be overwritten each time writer.c is run.
  2. Create a second program named reader.c. This program should read all the numbers from numbers.txt, calculate their product (multiply them all together), and print the final result to the console.

Hints:

  • For writer.c, open numbers.txt in "w" mode.
  • For reader.c, open numbers.txt in "r" mode and use the while (fscanf(...) != EOF) loop.
  • In reader.c, remember to initialize your product variable to 1, not 0!

This exercise separates the writing and reading logic, allowing you to focus on each part of the file I/O lifecycle individually.

Conclusion

You have now learned one of the most practical and essential skills in C programming: persisting data to files. This ability allows your programs to save their state, process large data sets, and interact with the broader operating system environment.

Key Takeaways:

  • File operations revolve around a FILE pointer, which acts as a handle to the file.
  • fopen() opens a file with a specific mode ("r", "w", "a"), returning the FILE pointer.
  • fprintf() writes formatted data to a file, just as printf() writes to the console.
  • fscanf() reads formatted data from a file, just as scanf() reads from the console.
  • The while (fscanf(...) != EOF) loop is the standard way to process a text file until its end.
  • Always fclose() a file after you are done to save all changes and release system resources.

Preview of the Next Lesson:
In our examples, we added a simple check to see if fopen() returned NULL. But what if an error happens during a read or write operation? In the next lesson, we will focus on performing robust error checking when opening and operating on files, ensuring your programs can handle unexpected issues gracefully.

Can't find a good explanation? Sign up and we'll make it for you

Sign up