Reputation: 523
I understand the workings of ftell() and fseek() in C, but for this question I couldn't find any precise answer anywhere, including from the closest post on StackOverflow(LINK).
So can you please answer the following:
The function fills the fpos_t object pointed by pos with the information needed from the stream's position indicator to restore the stream to its current position
Upvotes: 3
Views: 842
Reputation: 140826
Besides the reasons mentioned in the other answers, it might be necessary to use fgetpos
and fsetpos
if you are working with very large files, files that contain more than LONG_MAX
bytes. This is a real concern on systems where LONG_MAX
is 231 − 1; files with more than two billion bytes in them are not that uncommon nowadays.
If you are on a system that implements POSIX.1-2001, there is a better alternative, which is to #define _FILE_OFFSET_BITS 64
before including any system header files, and then use fseeko
and ftello
. These are just like fseek
and ftell
except that they take/return an off_t
quantity, which, provided you have made the above #define
, is guaranteed to be an integer type that can represent 263 − 1, which ought to be enough for anybody. This is better because you can do arithmetic on off_t
; you can't use fpos_t
to go somewhere you haven't already been. But if you're not on a POSIX system, fgetpos
and fsetpos
might be your only option.
(Note that some systems will give you an fpos_t
that can't represent a file offset greater than LONG_MAX
bytes. On some of those, applying the same #define _FILE_OFFSET_BITS 64
setting will help. On others, you're just completely out of luck if you want a huge file.)
Upvotes: 2
Reputation: 279385
Not quite. Clues can be found from Beej:
On virtually every system (and certainly every system that I know of), people don't use these functions, using ftell() and fseek() instead. These functions exist just in case your system can't remember file positions as a simple byte offset.
And Linux man pages:
On some non-UNIX systems, an fpos_t object may be a complex object and these routines may be the only way to portably reposition a text stream.
And on Windows:
It assumes that any \n character in the buffer was originally a \r\n sequence that had been normalized when the data was read into the buffer.
That is to say, files that aren't (Windows-linebreak) text files go wrong in Windows when opened in text mode because fsetpos
is assuming the file really was a (Windows-linebreak) text file and therefore cannot contain a \n
with no \r
.
The C11 standard says (my emphasis):
7.21.2/6:
Each wide-oriented stream has an associated mbstate_t object that stores the current parse state of the stream. A successful call to fgetpos stores a representation of the value of this mbstate_t object as part of the value of the fpos_t object. A later successful call to fsetpos using the same stored fpos_t value restores the value of the associated mbstate_t object as well as the position within the controlled stream.
Note that fseek
and ftell
have nothing to say about the mbstate_t
object: they do not report or restore it. So on wide-oriented streams (that is to say, streams on which you've used wide-oriented I/O functions) they only reset the file position, not (if the implementation actually has more than one possible value of a mbstate_t
object) the whole state of the stream.
Wide-oriented streams aren't the same thing as text streams, it's just that reading wide text files is the common use for them. Actually fseek
and ftell
are documented to be able to reset the file position on text files, provided you use them correctly. So I believe (I might be wrong) that fsetpos
and fgetpos
are only required when using wide I/O functions on the stream.
Upvotes: 2
Reputation: 73542
fgetpos()
and fsetpos()
are relevant for both text and binary mode.
The advantage of fgetpos()
is that is keeps the full position in the stream, including its internal state, so that you can restore is later. This works whether you are in text mode or not. This is especially important if you are using wide oriented streams or mix fgetc()
and fgetwc()
in the same file, because some locale use a state dependent multibyte encoding (state depends on previous reads).
fseek()
and ftell()
can also work with text and binary mode. However there is an important restriction in text mode: you should only use fseek()
with 0 or a value previously returned by ftell()
(in binary mode you can use whatever value you want). This is because the text mode reading can change the number of bytes returned from reading compared to the bytes effectively in the file (typical example, the 2 CR+LF bytes in a windows file which are converted to a signe LF byte).
As ftell()
only returns a long int
offset, it can't keep track of the multibyte state if this would be needed. So using fseek()
might loose this state.
Upvotes: 4