C course menu
File Handling in C: fopen, fprintf, fgets, fread, fwrite and fclose
Learn file input and output in C: opening files with fopen and its modes, checking for errors, writing text with fprintf and fputs, reading lines with fgets, reading formatted data with fscanf, binary files with fwrite and fread, fseek and ftell, and always closing files.
On this page
Programs often need data that outlives a single run: logs, settings, records. The C standard library handles files through a FILE * pointer, using functions very similar to the console ones you already know.
Opening and closing#
fopen(path, mode) opens a file and returns a FILE *, or NULL on failure (the file does not exist, permission denied, and so on). fclose closes it and flushes any buffered output:
FILE *fp = fopen("data.txt", "r");
if (fp == NULL) {
perror("data.txt"); /* prints the reason, e.g. "No such file or directory" */
return 1;
}
/* ... use fp ... */
fclose(fp);Add b ("rb", "wb") for binary files. On Windows, text mode converts \n to \r\n when writing, and binary mode does not; on Linux and macOS the two are the same.
Writing and reading text#
#include <stdio.h>
int main(void) {
FILE *out = fopen("marks.txt", "w");
if (out == NULL) { perror("marks.txt"); return 1; }
fprintf(out, "Asha 87\n");
fprintf(out, "Ravi 92\n");
fputs("Meena 78\n", out);
fclose(out);
FILE *in = fopen("marks.txt", "r");
if (in == NULL) { perror("marks.txt"); return 1; }
char line[100];
int n = 0;
while (fgets(line, sizeof line, in) != NULL) {
printf("line %d: %s", ++n, line); /* line already ends in '\n' */
}
fclose(in);
return 0;
}line 1: Asha 87
line 2: Ravi 92
line 3: Meena 78fgets returns NULL at the end of the file, which ends the loop. This is the standard way to read a text file line by line.
Reading formatted data#
fscanf reads values the way scanf does. Check its return value, the number of items it read, to stop at the end of the file or at bad data:
#include <stdio.h>
int main(void) {
FILE *f = fopen("scores.txt", "w");
if (f == NULL) return 1;
fprintf(f, "Asha 87\nRavi 92\nMeena 78\n");
fclose(f);
f = fopen("scores.txt", "r");
if (f == NULL) return 1;
char name[32];
int mark, total = 0, count = 0;
while (fscanf(f, "%31s %d", name, &mark) == 2) {
total += mark;
count++;
}
fclose(f);
printf("%d students, average %.2f\n", count, (double)total / count);
return 0;
}3 students, average 85.67For real-world input it is more robust to read each line with fgets and parse it with sscanf, so one bad line cannot leave the reader stuck mid-line.
Appending#
#include <stdio.h>
int main(void) {
for (int run = 1; run <= 3; run++) {
FILE *log = fopen("app.log", "a");
if (log == NULL) return 1;
fprintf(log, "run %d\n", run);
fclose(log);
}
FILE *in = fopen("app.log", "r");
if (in == NULL) return 1;
int c;
while ((c = fgetc(in)) != EOF) putchar(c);
fclose(in);
return 0;
}run 1
run 2
run 3Binary files: fwrite and fread#
Text files are readable by people; binary files store the raw bytes of your data, which is compact and fast. fwrite(ptr, size, count, fp) and fread return how many items they processed:
#include <stdio.h>
typedef struct {
int id;
double price;
} Product;
int main(void) {
Product items[] = {{1, 49.5}, {2, 120.0}, {3, 15.25}};
FILE *f = fopen("products.bin", "wb");
if (f == NULL) return 1;
size_t written = fwrite(items, sizeof items[0], 3, f);
fclose(f);
printf("wrote %zu records\n", written);
Product loaded[3];
f = fopen("products.bin", "rb");
if (f == NULL) return 1;
size_t read = fread(loaded, sizeof loaded[0], 3, f);
fseek(f, 0, SEEK_END); /* jump to the end */
long size = ftell(f); /* position = file size */
fclose(f);
printf("read %zu records, file is %ld bytes\n", read, size);
for (size_t i = 0; i < read; i++) printf("%d: %.2f\n", loaded[i].id, loaded[i].price);
return 0;
}wrote 3 records
read 3 records, file is 48 bytes
1: 49.50
2: 120.00
3: 15.25Each Product is 16 bytes here (4 for id, 4 of padding, 8 for price). Binary files written this way depend on the compiler's struct layout, type sizes and byte order, so they are not portable between different systems. Use text formats (CSV, JSON) to exchange data.
Moving around a file#
fseek(fp, offset, origin): move to a position.originisSEEK_SET(start),SEEK_CUR(current position) orSEEK_END(end).ftell(fp): the current position in bytes.rewind(fp): back to the start.
Practice#
Practice exercise
Write a program that writes the numbers 1 to 10 to numbers.txt, one per line, then reads the file back and prints the count of even numbers and the sum of all numbers.
Show solution
#include <stdio.h>
int main(void) {
FILE *f = fopen("numbers.txt", "w");
if (f == NULL) { perror("numbers.txt"); return 1; }
for (int i = 1; i <= 10; i++) fprintf(f, "%d\n", i);
fclose(f);
f = fopen("numbers.txt", "r");
if (f == NULL) { perror("numbers.txt"); return 1; }
int n, evens = 0, sum = 0;
while (fscanf(f, "%d", &n) == 1) {
sum += n;
if (n % 2 == 0) evens++;
}
fclose(f);
printf("evens %d, sum %d\n", evens, sum);
return 0;
}evens 5, sum 55Key takeaway#
Finished this lesson?