File Handling in C
Read and write files! Learn fopen, fclose, fprintf, fscanf, and more. Save data permanently and load it back.
Track Your Progress
Sign in to save your learning progress
What You Will Learn
- ✓Open files with different modes (r, w, a)
- ✓Read and write text files
- ✓Handle binary files
- ✓Check for errors when working with files
01What is File Handling?
?Why Do We Need Files?
Think about what happens when you close your program — all your variables vanish! Files solve this problem.
Variables (RAM)
Files (Disk)
Save Games
Player progress
Logs
Error tracking
Config Files
User settings
Data Export
CSV, reports
Understanding FILE* — The Bookmark Analogy
Imagine a FILE* as a smart bookmark in a book:
data.txt
File on Disk
FILE *fp
Your Bookmark
Your Bookmark Tracks:
- Position — which line you're reading
- Mode — reading or writing?
- Buffer — cached data for speed
- Status — any errors? end of file?
The 3-Step Process:
fopen() → Get bookmarkread/write → Use bookmarkfclose() → Return bookmarkAlways check if fopen() returns NULL! It means the file couldn't be opened (doesn't exist, no permission, disk full, etc.)
Text Files
- • Human-readable content
- • Each line ends with newline
- • Examples: .txt, .csv, .html
- • Use: fgets, fputs, fprintf, fscanf
Binary Files
- • Raw bytes, not readable
- • Exact memory representation
- • Examples: .exe, .bin, .dat
- • Use: fread, fwrite
| Function | Purpose | Header |
|---|---|---|
| fopen() | Open a file | <stdio.h> |
| fclose() | Close a file | <stdio.h> |
| fgets() / fputs() | Read/write string (line) | <stdio.h> |
| fgetc() / fputc() | Read/write single char | <stdio.h> |
| fprintf() / fscanf() | Formatted read/write | <stdio.h> |
| fread() / fwrite() | Binary read/write | <stdio.h> |
| fseek() / ftell() | File position | <stdio.h> |
02The FILE Structure
What is FILE?
FILE is a structure defined in <stdio.h>. It contains information about the file being accessed. You never access its members directly - you always use FILE * (a pointer) and functions like fopen, fread, etc.
The FILE structure contains (simplified):
char *buffer; /* Data buffer */
int bufferSize; /* Size of buffer */
char *currentPos; /* Current position in buffer */
int fileDescriptor; /* OS file handle */
int mode; /* Read/write mode */
int eof; /* End-of-file indicator */
int error; /* Error indicator */
How file operations work:
Why Buffering?
Disk operations are slow. The buffer collects data and writes/reads in larger chunks, making file operations much faster.
03Opening & Closing Files
fopen() Syntax
FILE *fopen(const char *filename, const char *mode);
- • filename: Path to the file
- • mode: How to open (read, write, append, etc.)
- • Returns: FILE pointer, or NULL if failed
1#include <stdio.h>23int main() {4 // Open file for reading5 FILE *file = fopen("data.txt", "r");6 7 // Always check if file opened!8 if (file == NULL) {9 printf("Error: Cannot open file!\n");10 return 1;11 }12 13 printf("File opened successfully!\n");14 15 // Always close when done!16 fclose(file);17 18 return 0;19}File opened successfully!
Always Close Files!
Not closing files can cause: data loss (buffer not flushed), resource leaks, and file locks. Always use fclose()!
04File Modes
"r"Read Only
Opens existing file
Starts at beginning
Fails if missing
"w"Write Only
Creates or overwrites
ERASES old content!
✓ Creates if missing
"a"Append Only
➕ Adds to end
✓ Keeps old content
✓ Creates if missing
Combined Modes (Read + Write)
"r+"Read & Write
File must exist
"w+"Read & Write
Erases content!
"a+"Read & Append
Write at end only
| Mode | Read | Write | Create | Truncate | Position |
|---|---|---|---|---|---|
| "r" | ✓ | ✗ | ✗ | ✗ | Start |
| "w" | ✗ | ✓ | ✓ | ✓ | Start |
| "a" | ✗ | ✓ | ✓ | ✗ | End |
| "r+" | ✓ | ✓ | ✗ | ✗ | Start |
| "w+" | ✓ | ✓ | ✓ | ✓ | Start |
| "a+" | ✓ | ✓ | ✓ | ✗ | End |
Text vs Binary Mode
Add "b" to any mode for binary files:"rb","wb","ab", etc.
Text Mode (default)
- • Human-readable content
- • Newline translations (Windows: \r\n ↔ \n)
- • .txt, .csv, .json, .html
Binary Mode
- • Raw bytes, exact copy
- • No translations
- • .exe, .png, .mp3, structs
05Reading Text Files
Method 1: fgetc() - Read Character by Character
1#include <stdio.h>23int main() {4 FILE *file = fopen("data.txt", "r");5 if (file == NULL) return 1;6 7 int ch;8 while ((ch = fgetc(file)) != EOF) {9 putchar(ch); // Print character10 }11 12 fclose(file);13 return 0;14}Method 2: fgets() - Read Line by Line (Recommended)
1#include <stdio.h>23int main() {4 FILE *file = fopen("data.txt", "r");5 if (file == NULL) return 1;6 7 char line[256];8 9 // fgets reads until newline or buffer full10 while (fgets(line, sizeof(line), file) != NULL) {11 printf("%s", line); // line includes \n12 }13 14 fclose(file);15 return 0;16}Method 3: fscanf() - Formatted Reading
1#include <stdio.h>23int main() {4 FILE *file = fopen("students.txt", "r");5 if (file == NULL) return 1;6 7 char name[50];8 int age;9 float grade;10 11 // File contains: "Alice 20 3.8"12 while (fscanf(file, "%s %d %f", name, &age, &grade) == 3) {13 printf("Name: %s, Age: %d, Grade: %.1f\n", name, age, grade);14 }15 16 fclose(file);17 return 0;18}Name: Alice, Age: 20, Grade: 3.8
06Writing Text Files
Method 1: fputc() - Write Character
1#include <stdio.h>23int main() {4 FILE *file = fopen("output.txt", "w");5 if (file == NULL) return 1;6 7 fputc('H', file);8 fputc('i', file);9 fputc('!', file);10 fputc('\n', file);11 12 fclose(file);13 printf("Written to output.txt\n");14 return 0;15}Method 2: fputs() - Write String
1#include <stdio.h>23int main() {4 FILE *file = fopen("output.txt", "w");5 if (file == NULL) return 1;6 7 fputs("Hello, World!\n", file);8 fputs("This is line 2\n", file);9 10 fclose(file);11 return 0;12}Method 3: fprintf() - Formatted Writing (Most Used)
1#include <stdio.h>23int main() {4 FILE *file = fopen("report.txt", "w");5 if (file == NULL) return 1;6 7 char name[] = "Alice";8 int age = 25;9 float score = 95.5;10 11 // Just like printf, but to file!12 fprintf(file, "Name: %s\n", name);13 fprintf(file, "Age: %d\n", age);14 fprintf(file, "Score: %.1f\n", score);15 16 fclose(file);17 printf("Report saved!\n");18 return 0;19}Name: Alice
Age: 25
Score: 95.5
07Binary Files
When to Use Binary?
Use binary for structs, arrays, images, or any raw data. Binary is faster and more compact than text, but not human-readable.
fwrite() and fread() Syntax
fwrite(ptr, size, count, file);
fread(ptr, size, count, file);
- • ptr: Pointer to data
- • size: Size of each element
- • count: Number of elements
- • file: FILE pointer
Write and Read a Struct
1#include <stdio.h>23struct Student {4 char name[50];5 int age;6 float grade;7};89int main() {10 struct Student s1 = {"Alice", 20, 3.8};11 12 // Write struct to binary file13 FILE *file = fopen("student.dat", "wb");14 if (file == NULL) return 1;15 16 fwrite(&s1, sizeof(struct Student), 1, file);17 fclose(file);18 19 // Read struct back20 struct Student s2;21 file = fopen("student.dat", "rb");22 if (file == NULL) return 1;23 24 fread(&s2, sizeof(struct Student), 1, file);25 fclose(file);26 27 printf("Name: %s, Age: %d, Grade: %.1f\n", 28 s2.name, s2.age, s2.grade);29 30 return 0;31}Name: Alice, Age: 20, Grade: 3.8
Write and Read Array
1#include <stdio.h>23int main() {4 int arr[] = {10, 20, 30, 40, 50};5 int n = 5;6 7 // Write array8 FILE *file = fopen("numbers.bin", "wb");9 fwrite(arr, sizeof(int), n, file);10 fclose(file);11 12 // Read array13 int loaded[5];14 file = fopen("numbers.bin", "rb");15 fread(loaded, sizeof(int), n, file);16 fclose(file);17 18 for (int i = 0; i < n; i++) {19 printf("%d ", loaded[i]);20 }21 22 return 0;23}10 20 30 40 50
08File Positioning
The Position Indicator (Cursor)
Every file has an invisible cursor that tracks where you are in the file.
data.txt contents:
↑ Position = 5 (ftell returns 5)
SEEK_SETFrom beginning
fseek(f, 5, SEEK_SET)
→ Go to byte 5
SEEK_CURFrom current
fseek(f, 3, SEEK_CUR)
→ Move 3 bytes forward
SEEK_ENDFrom end
fseek(f, -2, SEEK_END)
→ 2 bytes before end
| Function | Purpose | Syntax |
|---|---|---|
| fseek() | Move to position | fseek(file, offset, origin) |
| ftell() | Get current position | long pos = ftell(file) |
| rewind() | Go to start | rewind(file) |
fseek() Origin Constants
| Constant | Value | Meaning |
|---|---|---|
| SEEK_SET | 0 | Beginning of file |
| SEEK_CUR | 1 | Current position |
| SEEK_END | 2 | End of file |
1#include <stdio.h>23int main() {4 FILE *file = fopen("data.txt", "r");5 if (file == NULL) return 1;6 7 // Get file size8 fseek(file, 0, SEEK_END); // Go to end9 long size = ftell(file); // Get position = size10 printf("File size: %ld bytes\n", size);11 12 // Go back to start13 rewind(file); // Same as fseek(file, 0, SEEK_SET)14 15 // Read first character16 int ch = fgetc(file);17 printf("First char: %c\n", ch);18 19 // Skip 5 characters from current position20 fseek(file, 5, SEEK_CUR);21 ch = fgetc(file);22 printf("6th char: %c\n", ch);23 24 fclose(file);25 return 0;26}09Error Handling
| Function | Purpose |
|---|---|
| feof(file) | Returns non-zero if end-of-file reached |
| ferror(file) | Returns non-zero if error occurred |
| clearerr(file) | Clear error and EOF flags |
| perror("msg") | Print error message |
1#include <stdio.h>23int main() {4 FILE *file = fopen("missing.txt", "r");5 6 if (file == NULL) {7 perror("Error opening file");8 return 1;9 }10 11 char buffer[100];12 while (fgets(buffer, sizeof(buffer), file) != NULL) {13 printf("%s", buffer);14 }15 16 // Check why loop ended17 if (feof(file)) {18 printf("\nEnd of file reached.\n");19 }20 if (ferror(file)) {21 printf("\nError reading file!\n");22 }23 24 fclose(file);25 return 0;26}Error opening file: No such file or directory
!Code Pitfalls: Common Mistakes & What to Watch For
These are the most common mistakes that trip up beginners. Study them carefully to avoid hours of debugging!
Not Checking fopen() Return
FILE *f = fopen("x.txt", "r");
fprintf(f, "Hi"); // Crash if NULL!
FILE *f = fopen("x.txt", "r");
if (f == NULL) return 1;
Forgetting to Close File
Always fclose(file) to flush buffer and release resources.
Using "w" Instead of "a"
"w" erases existing content! Use "a" to append without erasing.
Wrong Mode for Binary
Always use "rb"/"wb" for binary files. Text mode can corrupt binary data!
12Frequently Asked Questions
Q:What's the difference between text and binary mode?
A: Text mode translates newlines (Windows uses \r\n, Unix uses \n) and may alter certain characters. Binary mode ("rb"/"wb") reads/writes bytes exactly as-is. Use text for .txt, .csv; use binary for images, executables, structs.
Q:What happens if I don't close a file?
A: Buffered data might not be written, the file remains locked, and you waste system resources. The OS closes files at program exit, but for long-running programs, you can run out of file descriptors. Always fclose() when done!
Q:How do I check if a file exists before opening?
A: Try opening it and check for NULL:if (fopen("file.txt", "r") == NULL). Or use access() from <unistd.h>. Note: there's always a race condition — the file could be deleted between checking and opening.
Q:What's fseek and ftell used for?
A: fseek() moves the file position to read/write at specific locations. ftell() tells you the current position. Common pattern to get file size: seek to end, ftell, seek back to start.
Q:Should I use fread/fwrite or fprintf/fscanf?
A: Use fprintf/fscanf for human-readable text (config files, logs). Use fread/fwrite for binary data (images, raw structs, efficiency). Binary is faster and more compact but not human-readable or portable across architectures.
12Summary
Complete File I/O Workflow
fopen()Open
NULL checkVerify
read/writeUse
fclose()Close
Text File Functions
Binary File Functions
Mode Cheat Sheet
"r" = read"w" = write (erase!)"a" = append+ = add read+writeb = binary mode✓Safe File Handling Template
FILE *file = fopen("data.txt", "r");
if (file == NULL) {
perror("Error");
return 1;
}
// ... read or write ...
fclose(file);
Key Takeaways
- ✓FILE* = your bookmark/handle to a file
- ✓Always check if fopen() returns NULL
- ✓Always close files with fclose()
- ✓Text files: use fgets, fputs, fprintf
- ✓Binary files: use fread, fwrite with "rb"/"wb"
- "w" mode erases existing content!
Test Your Knowledge
Related Tutorials
UNIX/Linux System Calls
Interact with the operating system directly! Learn open, read, write, fork, exec, and other system calls that give C its power on UNIX/Linux.
Pointers in C
The most powerful feature in C! Pointers store memory addresses. Learn what they are, why they matter, and how to use them safely.
C errno.h Library Reference
Complete reference for errno.h - error handling with errno, perror(), strerror(), and common error codes.
Have Feedback?
Found something missing or have ideas to improve this tutorial? Let us know on GitHub!