Reading Files in C

Our first example demonstrates reading files in C. Reading and writing files are basic tasks needed for many C programs. Let’s look at some examples of reading files.

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

// This helper function will streamline our error checks
void check(int condition, const char* message) {
    if (condition) {
        perror(message);
        exit(1);
    }
}

int main() {
    // Perhaps the most basic file reading task is
    // slurping a file's entire contents into memory.
    FILE *file = fopen("/tmp/dat", "r");
    check(file == NULL, "Error opening file");

    fseek(file, 0, SEEK_END);
    long fsize = ftell(file);
    fseek(file, 0, SEEK_SET);

    char *string = malloc(fsize + 1);
    fread(string, fsize, 1, file);
    string[fsize] = 0;

    printf("%s", string);

    free(string);
    fclose(file);

    // You'll often want more control over how and what
    // parts of a file are read. For these tasks, start
    // by opening a file to obtain a FILE pointer.
    file = fopen("/tmp/dat", "r");
    check(file == NULL, "Error opening file");

    // Read some bytes from the beginning of the file.
    // Allow up to 5 to be read but also note how many
    // actually were read.
    char b1[6];
    size_t n1 = fread(b1, 1, 5, file);
    b1[n1] = '\0';
    printf("%zu bytes: %s\n", n1, b1);

    // You can also seek to a known location in the file
    // and read from there.
    fseek(file, 6, SEEK_SET);
    char b2[3];
    size_t n2 = fread(b2, 1, 2, file);
    b2[n2] = '\0';
    printf("%zu bytes @ %ld: %s\n", n2, ftell(file) - n2, b2);

    // The stdio library provides some functions that may
    // be helpful for file reading. For example, reads
    // like the ones above can be more robustly
    // implemented with fgets.
    fseek(file, 6, SEEK_SET);
    char b3[3];
    if (fgets(b3, sizeof(b3), file) != NULL) {
        printf("%zu bytes @ %ld: %s", strlen(b3), ftell(file) - strlen(b3), b3);
    }

    // There is no built-in rewind, but
    // fseek(file, 0, SEEK_SET) accomplishes this.
    fseek(file, 0, SEEK_SET);

    // The stdio library implements a buffered
    // reader that may be useful both for its efficiency
    // with many small reads and because of the additional
    // reading methods it provides.
    char b4[6];
    if (fgets(b4, sizeof(b4), file) != NULL) {
        printf("5 bytes: %s", b4);
    }

    // Close the file when you're done.
    fclose(file);

    return 0;
}

To run the program, first create a test file:

$ echo "hello" > /tmp/dat
$ echo "go" >>   /tmp/dat
$ gcc reading-files.c -o reading-files
$ ./reading-files
hello
go
5 bytes: hello
2 bytes @ 6: go
2 bytes @ 6: go
5 bytes: hello

This example demonstrates various methods of reading files in C, including reading entire files, reading specific portions, seeking to different positions, and using buffered reading. The C standard library provides functions like fopen, fread, fseek, and fgets for file operations.

Next, we’ll look at writing files.