Programming in C

File I/O

Gerald Senarclens de Grancy

Purpose of File I/O

  • Store persistent data
    • Write the results of your computations to files
    • Keep a log of errors
    • Store intermediate results
  • Load previously stored files

File Types

Text

+
Human readable
Multiple powerful standards like CVS, XML, JSON and YAML
Can usually be compressed
-
Hard to parse manually
Require more memory

Binary

+
Require less memory
Are easy to write and load if the exact format is known
-
Not human readable
Editing with a hex editor is tedious
Cannot be read when the format is not known

C API

All required functions are provided by <stdio.h>

fopen(.) opens files; if opening fails, NULL is returned

FILE *fopen(const char *pathname, const char *mode);

fprintf(.) and fwrite(.) write text and binary data to open files

int fprintf(FILE *stream, const char *format, ...);
int fputc(int c, FILE *stream);
int fputs(const char *s, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

fclose(.) writes buffered output and frees the file pointer's resources

int fclose(FILE *stream);  // on successful completion, 0 is returned

Text Files

Example: Writing Text

#include <stdio.h>  // provides fopen, fprintf and fclose

int main() {
int num = 15;
FILE* f = fopen("data.txt", "w"); // open for writing

if(f == NULL) { // we have to check if opening was successful
fprintf(stderr, "Error!");
return 1;
}

fprintf(f, "%d\n", num);
fprintf(f, "This is a text\n");
fclose(f);

return 0;
}
Download write_text.c

Example: Appending Text

#include <stdio.h>
#include <stdlib.h>

int main() {
FILE* f = fopen("data.txt", "a"); // open for appending

if(f == NULL) { // we have to check if opening was successful
fprintf(stderr, "Error!");
return EXIT_FAILURE;
}

fprintf(f, "%.2lf\n", 36.8);
fprintf(f, "Additional text\n");
fclose(f);

return 0;
}
Download append_text.c

Reading Text

#include <stdio.h>
int main() {
int num;
FILE* f = fopen("data.txt","r");
if(f == NULL) {
fprintf(stderr, "Error!");
return 1;
}
char line[100]; // a fixed size buffer for reading
fgets(line, sizeof(line), f);
sscanf(line, "%d\n", &num);
printf("Value in the file times two: %d\n", num * 2);
fgets(line, sizeof(line), f);
puts(line);
fclose(f);
return 0;
}
Download read_text.c

Binary Files

Example: Writing Data

#include <stdio.h>
typedef struct data {
int first;
int second;
} Data;
int main() {
Data d = {.first=1724, .second=255};
FILE* f = fopen("data.bin","wb");
if (f == NULL) { fputs("Error!", stderr); return 1; }
fwrite(&d, sizeof(Data), 1, f);
fclose(f);
return 0;
}
Download write_binary.c

Example: Reading Data

#include <stdio.h>
typedef struct data {
int first;
int second;
} Data;
int main() {
Data d;
FILE* f = fopen("data.bin","rb");
if (f == NULL) { fputs("Error!", stderr); return 1; }
fread(&d, sizeof(d), 1, f);
fclose(f);
printf("first: %d, second: %d\n", d.first, d.second);
return 0;
}
Download read_binary.c

Example: Write Array

#include <stdio.h>
#include <limits.h>

int main() {
unsigned int arr[] = { 0, UINT_MAX, 255, 0xff000000, 1724 };
FILE* f = fopen("array.bin","wb");
if (f == NULL) { fputs("Error!", stderr); return 1; }
fwrite(arr, sizeof(unsigned int), sizeof(arr) / sizeof(unsigned int), f);
fclose(f);
return 0;
}
Download write_array.c

Read Binary Data With a Hex Editor (eg. Okteta)

Start by investigating the file size (eg. ls -l)

Decode the values of the array: xxd [-b] file.bin (hint: endianness)

Dec Hex  Bin      Dec Hex  Bin
  0   0 0000        8   8 1000
  1   1 0001        9   9 1001
  2   2 0010       10   A 1010
  3   3 0011       11   B 1011
  4   4 0100       12   C 1100
  5   5 0101       13   D 1101
  6   6 0110       14   E 1110
  7   7 0111       15   F 1111
      

Exercise

  1. Write your name in a text file. Then write a C program to read that file and print its content to stdout.
  2. Write a C program that loads the array written by write_array.c. The program must print all numbers in the array to stdout, separated by commas.

Questions
and feedback...