Position inside streams

Location
  1. Courses

    /

  2. Complete C++ Course

    /

  3. The C Standard Library

    /

  4. File IO

    /

  5. Position inside streams

The cursor of streams

Streams have virtual cursors that specify from where inside the source (For example a file) the data will be read/written from/to. The C Standard Library provides 5 functions to change and retrieve the position of the cursor of a stream object.

Retrieving the position of the cursor inside a stream

There are two functions used to retrieve the position of the cursor of a stream. The header of the first one is long ftell(FILE* stream). The argument is the stream to read the cursor position from. If the operation is successful, it returns the position of the cursor. Otherwise, -1 is returned. With binary streams, the cursor position represents the number of bytes between the start of the stream and the current cursor position. However, in streams opened in text mode, the value might not be meaningful, and therefore should be used only to save the cursor position in order to set it back later.

Note that the returned value is of type long int. That means that the maximum position the cursor can be set to is limited by the maximum value that can be represented by the type long. If the type long is defined with a weight of 64 bits, this is not a problem. However, if it is defined with 32 bits, that means that we can not read bytes, from a stream, that are above the index (232/2-1) (Which equals 2 147 483 647 bytes or about 2.15 GB) and we can not output files bigger than about 2.15 GB.

If this is problematic, a solution would be to use an other library that provides more advanced features to handle files.

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
#include <stdio.h> int main() { char array[10]; FILE * file = fopen("test.bin", "rb"); // Retrieves the cursor position of the stream 'file'. Then prints it. long pos = ftell(file); printf("%ld\n", pos); // "0" is printed into the console. // Reads 10 bytes from the stream 'file', to 'array'. fread(array, 1, 10, file); // Retrieves the cursor position of the stream 'file'. Then prints it. pos = ftell(file); printf("%ld\n", pos); // "10" is printed into the console. fclose(file); return 0; }

The header of the other function is int getpos(FILE* stream, fpos_t* pos). The first argument is the stream to read the cursor position from and the second one is a pointer to an object of the structure type fpos_t to which the cursor position of the stream will be written to. The structure fpos_t is used to represent a position inside a stream. It should not be used directly, but instead used as argument to the function fsetpos to set the cursor of a stream back to that position. In case of success, it returns 0.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h> int main() { FILE * file = fopen("test.txt", "r"); int num; // Reads an integer from the stream 'file'. fscanf(file, "%d", &num); fpos_t pos; //Retrieves the position inside the stream 'file' into the object 'pos'. fgetpos(file, &pos); fclose(file); return 0; }

Setting the position of the cursor of a stream

There are 3 functions used to set the position of the cursor inside a stream. The header of the first one is int fseek(FILE* stream, long offset, int from). The first argument is the stream from which we want to change the cursor position. The second one is the position of the cursor relatively to the location represented by last parameter. If the operation is successful, 0 is returned.

The last argument may take the value of one of the following macros:

MacroMeaning
SEEK_SETStart of the file.
SEEK_CURCurrent cursor position.
SEEK_ENDEnd of the file.

Warning: The macro SEEK_END is not guaranteed to be supported. Therefore, using it may cause compatibility issues with some compilers.

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
#include <stdio.h> int main() { FILE * file = fopen("test.txt", "rb"); // The cursor position starts at 0. // Sets the cursor of the stream 'file' at 5 bytes from the start of the stream. fseek(file, 5, SEEK_SET); // Sets the cursor of the stream 'file' at 5 bytes from the current cursor position of the stream. fseek(file, 5, SEEK_CUR); // Retrieves the cursor position of the stream 'file'. long pos = ftell(file); // Sets the cursor of 'file' to the start of the stream. fseek(file, 0, SEEK_SET); // Sets the cursor back to the position saved inside the variable pos. fseek(file, pos, SEEK_SET); return 0; }

Note that if the stream is in text mode, the function fseek should only be used with values returned by the function ftell.

The header of the second function is int fsetpos(FILE* stream, const fpos_t* pos). It is used to set the position of the cursor of a stream using an object of type fpos_t, previously retrieved by the function fgetpos. The first argument is the stream from which to set the cursor position and the last one is a pointer to the object of type fpos_t representing the position inside the stream. In case of success, 0 is returned.

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("test.txt", "r"); fpos_t pos; float n; /* Reads a floating-point number from the stream 'file'. */ fscanf(file, "%f", &n); /* Retrieves the position inside the stream 'file', into the object 'pos'. */ fgetpos(file, &pos); double n2; /* Reads a floating-point number (As a value of type double) from the stream 'file'. */ fscanf(file, "%lf", &n2); /* Sets the cursor of stream 'file' back to the position saved inside the object 'pos'. */ fsetpos(file, &pos); return 0; }

The last function is used to set the cursor of a stream to the start of it. The header of the function is void rewind(FILE* stream). It takes, as argument, the stream from which to set the cursor to the beginning.

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
#include <stdio.h> int main() { FILE * file = fopen("test.txt", "r"); // The cursor of the stream 'file' starts at 0. int num; // Reads an integer from the stream 'file'. fscanf(file, "%d", &num); // Alters (Changes) the value of the variable num. num = 5; // Sets the cursors position back to the beginning of the stream 'file'. rewind(file); // Reads the same integer again. fscanf(file, "%d", &num); fclose(file); return 0; }

Note that functions that change the position of the cursor of a stream have the effect of discarding the characters added to it using the function ungetc.