C reading and writing text files

Write lines to a file with fprintf, read them back with fgets, and parse each line with sscanf.

C
#include <stdio.h>

int main(void) {
  FILE *file = fopen("lesson_data.txt", "w+");
  if (file == NULL) {
    printf("could not open the file\n");
    return 1;
  }
  fprintf(file, "alpha 3\nbeta 5\ngamma 8\nbad line\n");
  rewind(file);

  char line[64];
  int total = 0;
  int good = 0;
  while (fgets(line, sizeof line, file) != NULL) {
    char name[32];
    int value;
    if (sscanf(line, "%31s %d", name, &value) == 2) {
      printf("%s -> %d\n", name, value);
      total += value;
      good++;
    } else {
      printf("skipped a malformed line\n");
    }
  }
  fclose(file);
  remove("lesson_data.txt");
  printf("%d good lines, total %d\n", good, total);
  return 0;
}
Output
alpha -> 3
beta -> 5
gamma -> 8
skipped a malformed line
3 good lines, total 16

Explanation

C reads and writes files through a FILE pointer. fopen opens a file in a mode such as "w+" for writing and reading, fprintf writes formatted text, rewind moves back to the start, and fgets reads one line at a time into a buffer of a given size. fclose flushes and releases the file.

fopen returns NULL if the file cannot be opened, so the result must always be checked. fgets stops at the newline or when the buffer is full, and it never writes past the buffer size. sscanf parses a line that has already been read; checking that it returned the expected number of fields detects bad input. remove deletes the file afterwards.

Explore the dry run
Guided walkthroughReady
1#include <stdio.h>
2
3int main(void) {
4 FILE *file = fopen("lesson_data.txt", "w+");
5 if (file == NULL) {
6 printf("could not open the file\n");
7 return 1;
8 }
9 fprintf(file, "alpha 3\nbeta 5\ngamma 8\nbad line\n");
10 rewind(file);
11
12 char line[64];
13 int total = 0;
14 int good = 0;
15 while (fgets(line, sizeof line, file) != NULL) {
16 char name[32];
17 int value;
18 if (sscanf(line, "%31s %d", name, &value) == 2) {
19 printf("%s -> %d\n", name, value);
20 total += value;
21 good++;
22 } else {
23 printf("skipped a malformed line\n");
24 }
25 }
26 fclose(file);
27 remove("lesson_data.txt");
28 printf("%d good lines, total %d\n", good, total);
29 return 0;
30}

Follow the example

Start to inspect the source, values, and output. These prepared steps explain the published sample; grouped loop steps describe multiple iterations.

View the complete dry-run table
Prepared trace of the published program. Some rows group repeated iterations.
Step / lineWhat happensState after stepOutput so far
Open a file for writing and reading, creating or emptying it.—
—
Write four lines of text.—
—
Go back to the start of the file so the lines can be read.—
—
A good line has a word and a number. %31s limits the word to 31 characters, so it cannot overflow name.—
—
Each good line is printed and added up.—
alpha -> 3
beta -> 5
gamma -> 8
The last line has no number, so sscanf returns fewer than 2 fields and the line is skipped.—
alpha -> 3
beta -> 5
gamma -> 8
skipped a malformed line
3 + 5 + 8 = 16.—
alpha -> 3
beta -> 5
gamma -> 8
skipped a malformed line
3 good lines, total 16

Cost and common mistakes

O(n) for a file of n characters.

  • Never use gets, and never use a bare %s in scanf or sscanf, since both can overflow the buffer.
  • A line longer than the buffer is split across several fgets calls. Check whether the buffer ends with a newline if that matters.
  • Always check the result of fopen. Opening can fail because of permissions, a missing folder, or a full disk.

Try it yourself

Why is fclose important?

Reveal answer and reasoning

It flushes buffered data to the file and releases the file handle. Without it, data can be lost and handles leak.

Further reading