C file handling uses a FILE stream as the boundary between your program and persistent bytes. The important habits are to choose the correct open mode, check every operation that can fail, process bounded buffers, and close the stream on every path.
C provides file I/O through the <stdio.h> library. Files are accessed through a FILE pointer. Always close files after use with fclose().
| Mode | Description | File Exists | File Missing |
|---|---|---|---|
| "r" | Read text | Opens for reading | Returns NULL |
| "w" | Write text | Truncates to empty | Creates new file |
| "a" | Append text | Appends to end | Creates new file |
| "r+" | Read + Write | Opens for both | Returns NULL |
| "w+" | Write + Read | Truncates to empty | Creates new file |
| "a+" | Append + Read | Appends, reads from start | Creates new file |
| "rb" | Read binary | Opens for binary read | Returns NULL |
| "wb" | Write binary | Truncates | Creates new file |
| Function | Description |
|---|---|
| fopen(path, mode) | Opens a file; returns FILE* or NULL on failure |
| fclose(fp) | Closes the file and flushes buffer |
| fprintf(fp, fmt, ...) | Writes formatted text to file |
| fscanf(fp, fmt, ...) | Reads formatted data from file |
| fputc(c, fp) | Writes a single character |
| fgetc(fp) | Reads a single character |
| fputs(str, fp) | Writes a string (no newline added) |
| fgets(buf, n, fp) | Reads a line (up to n-1 chars) |
| fwrite(ptr, size, n, fp) | Writes n binary blocks of given size |
| fread(ptr, size, n, fp) | Reads n binary blocks of given size |
| fseek(fp, offset, origin) | Moves file position pointer |
| ftell(fp) | Returns current file position |
| rewind(fp) | Resets position to beginning |
| feof(fp) | Returns non-zero if end of file reached |
| ferror(fp) | Returns non-zero if an error occurred |
#include <stdio.h>
int main() {
FILE *fp;
// --- Write to file ---
fp = fopen("students.txt", "w");
if (fp == NULL) {
printf("Error opening file!\n");
return 1;
}
fprintf(fp, "Alice 20 3.85\n");
fprintf(fp, "Bob 22 3.20\n");
fprintf(fp, "Carol 21 3.65\n");
fclose(fp);
printf("Data written to students.txt\n");
// --- Read from file ---
fp = fopen("students.txt", "r");
if (fp == NULL) {
printf("Error opening file!\n");
return 1;
}
char name[50];
int age;
float gpa;
printf("\nReading from file:\n");
while (fscanf(fp, "%s %d %f", name, &age, &gpa) == 3) {
printf("Name: %-10s Age: %d GPA: %.2f\n", name, age, gpa);
}
fclose(fp);
return 0;
}
#include <stdio.h>
int main() {
FILE *src, *dest;
int ch;
src = fopen("students.txt", "r");
if (src == NULL) { printf("Cannot open source file\n"); return 1; }
dest = fopen("students_copy.txt", "w");
if (dest == NULL) { fclose(src); printf("Cannot create dest file\n"); return 1; }
// Copy character by character
while ((ch = fgetc(src)) != EOF) {
fputc(ch, dest);
}
fclose(src);
fclose(dest);
printf("File copied successfully!\n");
// Read back using fgets
dest = fopen("students_copy.txt", "r");
char line[100];
printf("\nContents of copy:\n");
while (fgets(line, sizeof(line), dest) != NULL) {
printf("%s", line);
}
fclose(dest);
return 0;
}
#include <stdio.h>
#include <string.h>
typedef struct {
char name[30];
int age;
float salary;
} Employee;
int main() {
Employee emp[3] = {
{"Alice", 30, 75000.0f},
{"Bob", 25, 60000.0f},
{"Carol", 35, 90000.0f}
};
// Write binary data
FILE *fp = fopen("employees.bin", "wb");
if (!fp) { printf("Cannot open file\n"); return 1; }
fwrite(emp, sizeof(Employee), 3, fp);
fclose(fp);
printf("Binary data written.\n");
// Read binary data
Employee read_emp[3];
fp = fopen("employees.bin", "rb");
if (!fp) { printf("Cannot open file\n"); return 1; }
int count = fread(read_emp, sizeof(Employee), 3, fp);
fclose(fp);
printf("\nRead %d records:\n", count);
for (int i = 0; i < count; i++) {
printf("%-10s Age: %d Salary: %.2f\n",
read_emp[i].name, read_emp[i].age, read_emp[i].salary);
}
// fseek and ftell
fp = fopen("employees.bin", "rb");
fseek(fp, sizeof(Employee), SEEK_SET); // skip first record
Employee second;
fread(&second, sizeof(Employee), 1, fp);
printf("\nSecond record: %s\n", second.name);
printf("File position: %ld bytes\n", ftell(fp));
fclose(fp);
return 0;
}
fopen returns NULL when the path, permissions, mode, or resource limits prevent opening the file. Passing that NULL pointer to other stdio functions causes undefined behavior.
Disk errors, full storage, interrupted operations, and stream failures can produce a short write. Check fwrite's return count, inspect ferror when it is short, and also check fflush or fclose because buffered errors may appear later.
Write mode creates the file or truncates an existing file to length zero. Use "a" for appending or "r+" when updating an existing file without immediate truncation, then seek carefully.
Explore 500+ free tutorials across 20+ languages and frameworks.