File binary IO

Location
  1. Courses

    /

  2. Quick C course

    /

  3. File binary IO

In the previous page, we learned to read/write from/to files in text mode. That way, numbers are represented as strings (text), not binary.

Here, we will learn to input/output the raw value of the variables (Their bytes).

Text mode vs binary mode

When dealing with binary data, we must open the files in binary mode, because in text mode, automatic conversions may be executed.

For example, with Windows, new lines are represented with two characters. Because of that, when we output the character (byte) '\n', a second character is automatically appended after it (The character '\r').

In binary mode, what we output is exactly what is written, without any change.

We open a file in binary mode by appending 'b' to the opening mode:

FILE *file = fopen("file.bin", "wb");

Outputting bytes

Let us define an array of 'int':

int array[] = {1, 2, 3, 4, 5};

We create/open a file in write/binary mode:

FILE *file = fopen("file.bin", "wb");

And, using the function 'fwrite', we write the bytes of the array to the file:

fwrite(array, sizeof(int), 5, file);

The first argument is the address of the first element to output, the second one is the size of one element and the third one is the number of elements to write.

Inputting bytes

We open a file in read/binary mode:

FILE *file = fopen("file.bin", "rb");

Using 'fread', we read bytes from that file in order to fill the array 'array':

fread(array, sizeof(int), 5, file);

The function 'fread' returns the number of elements successful read. Here we catch that number:

unsigned nbElementsRead = fread(array, sizeof(int), 5, file);

If the number returned is smaller than the third argument, that means that the end of the file has been reached before the function could read the number of elements requested.

We do not have to read the bytes into the array starting at the first element. Here we read 8 'int' into 'array' from the eleventh element:

fread(&array[10], sizeof(int), 8, file);

Retrieving the position of the cursor

When we execute input/output operations on an open file, its internal cursor moves. We can retrieve its position in bytes, relatively to the beginning of the file, using the function 'ftell':

unsigned pos = ftell(file);

The position of the cursor of a freshly open file starts at 0.

Setting the position of the cursor

Here we set the cursor at the beginning of the file:

fseek(file, 0, SEEK_SET);

Here we set it at 8 bytes from the start:

fseek(file, 8, SEEK_SET);

The last argument is a position within the file used as reference and the second one is the offset from it.

Here are the possible values for third argument:

ValueDescription
SEEK_SETFrom the beginning of the file.
SEEK_CURFrom the current position.
SEEK_ENDFrom the end of the file.

Here we move the cursor by 10 bytes from the current position:

fseek(file, 10, SEEK_CUR);

Here we place the cursor at the end of the file:

fseek(file, 0, SEEK_END);

Warning: The value 'SEEK_END' is not guaranteed to be supported by every C compiler.

fseek and ftell in text mode

Note that even though 'ftell' works with files open in text mode, in that case, the position returned does not necessarily represent the number of bytes between the cursor and the start of the file. The value returned can however be used with 'fseek' to set the cursor back to where it was when 'ftell' was called.

Output example

main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h> int main() { FILE *file = fopen("file.bin", "wb"); float array[] = {1.1, 2.2, 3.3, 4.4, 5.5}; // We output the bytes of 'array' into the file. fwrite(array, sizeof(float), 5, file); return 0; }

If we open the file with a text editor, we will see random characters:

The reason is that the bytes of the 'float' elements of the array are, wrongly, interpreted as characters by the text editor.

Input example

main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h> int main() { FILE *file = fopen("file.bin", "rb"); /* We define an array of 500 elements, so this is the maximum amount of 'float' we can read from the file at once. */ float array[500]; /* We read bytes from the file and interpret them as 'float' variables. We also retrieve the number of 'float' actually read. */ unsigned nbElementsRead = fread(array, sizeof(float), 500, file); /* If the amount of elements read is smaller than 500, then this is the amount contained inside the file. Otherwise, there may be others left unread. */ printf("Number of 'float' read: %d.\n", nbElementsRead); printf("Here are the value of the elements:\n"); // For each element read, we print its value. for(unsigned c=0; c < nbElementsRead; c++) printf("%f\n", array[c]); return 0; }