C Binary File I/O, Struct Serialization & fseek() Positioning Masterclass
Welcome to Phase 14 (Chapter 37): C Binary File I/O, Struct Serialization & fseek() Positioning Masterclass! While text files format values into human-readable ASCII strings, binary files write exact RAM byte images directly to disk. In this guide, you will master fwrite(), fread(), binary struct serialization, and random-access positioning with fseek().
Binary files store raw memory byte blocks without string conversion overhead.
| Feature | Text Files ("r", "w", "a") | Binary Files ("rb", "wb", "ab") |
|---|---|---|
| Data Storage | ASCII / UTF-8 Characters | Exact RAM Raw Bytes |
| Storage Size | Variable (Integer 1234567 = 7 bytes) | Fixed (32-bit int = 4 bytes) |
| Processing Speed | Slower (Requires parsing formatted text) | Ultra Fast (Direct RAM-to-Disk block copy) |
| Newline Translation | OS converts \n to \r\n on Windows | No translation (Pure byte fidelity) |
Binary I/O functions move blocks of memory between RAM and disk:
Binary I/O Function Signatures:
โข size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);
โข size_t fread(void *ptr, size_t size, size_t count, FILE *stream);
Passing &structInstance writes the entire C structure (including internal member bytes) in one single atomic I/O operation!
By default, file reading and writing happen sequentially. Functions in <stdio.h> allow moving the File Position Indicator to any arbitrary byte location:
โข fseek(fp, offset, origin): Moves file cursor. origin can be SEEK_SET (0), SEEK_CUR (current), or SEEK_END (file end).
โข ftell(fp): Returns current byte offset location from file start.
โข rewind(fp): Resets file pointer back to index 0.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int id;
char name[30];
double balance;
} Account;
int main(void) {
const char *db_file = "bank_accounts.dat";
Account accounts[3] = {
{101, "Ravi Kumar", 45000.50},
{102, "Anitha Roy", 89200.75},
{103, "Kiran Sharma", 12300.00}
};
FILE *fp = fopen(db_file, "wb");
if (!fp) { perror("Failed to create db"); return 1; }
fwrite(accounts, sizeof(Account), 3, fp);
fclose(fp);
printf("Successfully serialized 3 Account structs to binary file.\n");
fp = fopen(db_file, "rb");
if (!fp) { perror("Failed to open db"); return 1; }
fseek(fp, 0, SEEK_END);
long fileSize = ftell(fp);
printf("Total Binary File Size: %ld Bytes (%ld Accounts)\n", fileSize, fileSize / sizeof(Account));
int targetIndex = 1;
long offset = targetIndex * sizeof(Account);
fseek(fp, offset, SEEK_SET);
Account found;
if (fread(&found, sizeof(Account), 1, fp) == 1) {
printf("\n--- DIRECT RECORD LOOKUP (Index %d) ---\n", targetIndex);
printf("ID: %d | Name: %s | Balance: $%.2f\n", found.id, found.name, found.balance);
}
fclose(fp);
return 0;
} Q1: Why are binary files not portable across different CPU architectures?
Binary files write raw RAM memory bytes. Different CPUs have different Endianness (Little-Endian Intel vs Big-Endian Network) and struct padding alignment rules.
Q2: How do you find the exact byte size of a file in C?
Use fseek(fp, 0, SEEK_END); long size = ftell(fp); rewind(fp);.
Q3: What does the return value of fread() and fwrite() indicate?
They return the number of elements successfully read or written, NOT byte counts.
Q4: Why specify "b" in fopen() mode string ("rb", "wb")?
On Windows operating systems, opening files without "b" treats them as text files, automatically altering \r\n bytes which corrupts raw binary images.
Q5: What is struct padding risk during binary serialization?
Compilers insert padding hole bytes inside structures for RAM memory alignment. Writing raw structs writes these padding bytes, wasting disk space.