CFile IoIntermediate

fread() / fwrite()

Reads/writes binary blocks from/to a file stream.

Review the syntaxStudy the examplesOpen the coding app
size_t fread(void *ptr, size_t size, size_t count, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);

This static page keeps the syntax and examples indexed for search, while the coding app handles interactive exploration and saved references.

What it does

Overview

Reads/writes binary blocks from/to a file stream.

fread() and fwrite() are the standard C library functions for performing block-based binary input and output. Unlike character-oriented functions like fgetc() or formatted functions like fprintf(), these routines transfer raw memory patterns directly between a buffer and a file stream without translation. This makes them highly efficient for handling arrays, structures, and large data blocks. They operate using two granularity parameters: 'size' (the size of a single element) and 'count' (the number of elements to transfer). The functions return a representing the number of whole elements successfully processed. A return value less than 'count' signifies either the end-of-file (EOF) or a hardware/stream error. From a performance perspective, these functions are optimized for bulk transfers, especially when the buffer size aligns with the operating system's filesystem block size (typically 4KB or 8KB). However, developers must be wary of 'struct padding' and 'endianness' (byte order) when writing binary files intended for use on different CPU architectures or compilers, as the raw memory layout of a structure is not guaranteed to be portable.

Quick reference

Syntax

size_t fread(void *ptr, size_t size, size_t count, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);

Inputs

Parameters

ptrvoid* · Buffer to read into (fread) or data to write (fwrite).
sizesize_t · Size of each item in bytes.
countsize_t · Number of items to read/write.
streamFILE* · File stream opened in binary mode (e.g., "rb").

See it in practice

Examples

1

Saving and Loading Numeric Arrays

#include <stdio.h>

int main() {
    double constants[] = {3.14159, 2.71828, 1.61803};
    double results[3];
    FILE *f = fopen("math.bin", "wb+");

    if (f) {
        // Write the whole array at once
        fwrite(constants, sizeof(double), 3, f);
        
        // Rewind and read back
        rewind(f);
        fread(results, sizeof(double), 3, f);
        
        printf("Read: %.2f, %.2f, %.2f\n", results[0], results[1], results[2]);
        fclose(f);
    }
    return 0;
}
Output:
Read: 3.14, 2.72, 1.62

Demonstrates writing an array of doubles to a binary file and reading them back into a separate buffer using the size of the data type.

2

Handling Binary Structures

#include <stdio.h>

struct Player { int id; int level; };

int main() {
    struct Player p1 = {101, 5}, p2;
    FILE *file = fopen("save.dat", "wb");
    if (file) {
        fwrite(&p1, sizeof(struct Player), 1, file);
        fclose(file);
    }

    file = fopen("save.dat", "rb");
    if (file) {
        if (fread(&p2, sizeof(struct Player), 1, file) == 1) {
            printf("Player ID: %d, Level: %d\n", p2.id, p2.level);
        }
        fclose(file);
    }
    return 0;
}
Output:
Player ID: 101, Level: 5

Shows how to persist a C structure to disk. Note that using sizeof(struct Player) ensures all fields (and internal padding) are captured.

3

Robust Error and EOF Checking

#include <stdio.h>

int main() {
    char buffer[100];
    FILE *f = fopen("test.bin", "rb");
    if (!f) return 1;

    size_t items_read = fread(buffer, 1, 100, f);
    if (items_read < 100) {
        if (feof(f)) {
            printf("Successfully read %zu bytes until EOF.\n", items_read);
        } else if (ferror(f)) {
            perror("Error reading file");
        }
    }
    fclose(f);
    return 0;
}
Output:
Successfully read 42 bytes until EOF.

Illustrates how to use feof() and ferror() to differentiate between reaching the end of the file and encountering an actual I/O failure.

Debug faster

Common Errors

1

LogicError

Cause: Swapping the 'size' and 'count' arguments. While fread(buf, 1, 100, f) and fread(buf, 100, 1, f) read the same amount of data, their return values differ significantly.

Fix: Ensure 'size' is the size of one unit and 'count' is the number of units. If you use 'size=100' and only 50 bytes are available, fread returns 0 (zero full items), but with 'size=1', it returns 50.

size_t n = fread(buffer, 1024, 1, f); // Returns 0 if < 1024 bytes available
2

RuntimeError

Cause: Opening binary files in text mode ("r" or "w") on systems like Windows. This causes '\n' to be translated to '\r\n' (and vice versa), corrupting binary data like pointers or compressed bytes.

Fix: Always use the "b" flag (e.g., "rb", "wb", "ab") when calling fopen() for non-text data.

FILE *f = fopen("image.png", "r"); // WRONG: should be "rb"
3

SecurityError

Cause: Passing a 'count' value that exceeds the allocated capacity of the destination buffer ('ptr'), leading to a buffer overflow.

Fix: Always verify that (size * count) is less than or equal to the actual buffer size.

char buf[10]; fread(buf, 1, 100, f); // Buffer overflow

Runtime support

Compatibility

C89+

stdio.h; for binary files use modes "rb"/"wb" on Windows

Source: MDN Web Docs

Common questions

Frequently Asked Questions

Reads/writes binary blocks from/to a file stream.

ptr: Buffer to read into (fread) or data to write (fwrite). size: Size of each item in bytes. count: Number of items to read/write. stream: File stream opened in binary mode (e.g., "rb").

LogicError: Ensure 'size' is the size of one unit and 'count' is the number of units. If you use 'size=100' and only 50 bytes are available, fread returns 0 (zero full items), but with 'size=1', it returns 50. RuntimeError: Always use the "b" flag (e.g., "rb", "wb", "ab") when calling fopen() for non-text data. SecurityError: Always verify that (size * count) is less than or equal to the actual buffer size.