Introduction
Everything a program holds in its variables disappears when it ends. Files are how data survives. Saving and loading is the difference between a toy and a useful program, and C's file functions are close relatives of the printf and scanf you already know.
How it works
Opening. fopen(name, mode) opens a file and returns a FILE *, or NULL if it could not.
| Mode | Meaning |
|---|---|
"r" | read an existing file |
"w" | write, and empty the file first |
"a" | add to the end |
Why check for NULL. A file can be missing, locked or in a folder you cannot write to. These are normal events, not rare ones, and using a NULL file pointer crashes the program.
Writing. fprintf(f, ...) works just like printf, except that it writes to the file. fputs(text, f) writes a string.
Reading. fscanf(f, ...) works like scanf, and it returns how many values it read. fgets(buffer, size, f) reads one line, keeping the newline, and returns NULL at the end of the file.
Closing. fclose(f) finishes the work and releases the file. Written data may not reach the disk until then.
Reading a whole file. Do not count lines in advance. Let the read function say when it has run out:
#include <stdio.h>
#include <string.h>
int main(void) {
FILE *f = fopen("notes.txt", "w");
if (f == NULL) return 1;
fputs("first line\n", f);
fputs("second\n", f);
fclose(f);
f = fopen("notes.txt", "r");
if (f == NULL) return 1;
char line[50];
int count = 0;
while (fgets(line, sizeof line, f) != NULL) {
count++;
line[strcspn(line, "\n")] = '\0';
printf("%d: %s (%d)\n", count, line, (int)strlen(line));
}
fclose(f);
return 0;
}strcspn(line, "\n") finds where the newline is, so that writing a '\0' there removes it.
A note on these pages. In StepVioz, files are kept in memory while your program runs, and they disappear when it finishes. A program compiled on your own computer writes real files to its disk, using exactly the same code.
Syntax
FILE *f = fopen("data.txt", "r");
if (f == NULL) {
printf("Could not open the file\n");
return 1;
}
while (fscanf(f, "%d", &n) == 1) {
...
}
fclose(f);
Example
#include <stdio.h>
int main(void) {
FILE *out = fopen("marks.txt", "w");
if (out == NULL) {
printf("Could not create the file\n");
return 1;
}
fprintf(out, "%d %d\n", 72, 85);
fprintf(out, "%d %d\n", 64, 90);
fclose(out);
FILE *in = fopen("marks.txt", "r");
if (in == NULL) {
printf("Could not open the file\n");
return 1;
}
int a, b, total = 0;
while (fscanf(in, "%d %d", &a, &b) == 2) {
total += a + b;
}
fclose(in);
printf("Total %d\n", total);
return 0;
}Line by line
fopenwith"w"creates the file, and the program checks that it worked.- The two
fprintfcalls write two lines of numbers. fclosefinishes the writing.- The file is opened again, this time for reading.
fscanfreturns 2 as long as it finds two numbers, so the loop ends when the file does.- The total is printed after the file has been closed.
Expected result
Total 311
In the real world
Configuration files, logs and saved games are ordinary files. Databases are built on top of the same operations, with a great deal of extra care to survive a crash at the worst possible moment.
Common mistakes
- Not checking
fopenforNULL, and crashing on the next line. - Opening with
"w"when you meant"a", which erases what was there. - Forgetting
fclose, so that some data never gets written. - Using
while (!feof(f)), which runs one time too many. Test the result of the read instead.
Best practices
- Check every
fopen, and report the problem clearly. - Close each file as soon as you are done with it.
- Give
fgetsthe true size of your array, usingsizeof.
Summary
fopen opens a file and returns NULL on failure. fprintf and fputs write, fscanf and fgets read, and their results tell you when the file has ended. fclose finishes the job.
Quick check
Key takeaways
- fopen returns NULL when it fails, so check every call.
- Every fopen needs an fclose.
- Loop on what the read function returns, not on a guess.
Practice problems for this lesson
My notes
Write down what you want to remember from this lesson. Notes are saved on this device as you type, and appear on your dashboard.