Reputation: 21364
If I have a text file with the following content opened as binary
1234567890
a call like this:
fseek(fp, 5L, SEEK_SET);
give me 6 when I call (char)fgetc(fp)
because I offset 5 byte from byte 0 (not start from 1 but from 2)
but If I do:
fseek(fp, -3L, SEEK_END);
give me 8 and not 7 when I call (char)fgetc(fp)
.
Why? It seems as with SEEK_END
the offset doesn't start from the previous byte after the last.
Upvotes: 6
Views: 25787
Reputation: 1263
It all comes down to visualization.
I think of a file as a zero based array. I.e. byte at index 0
etc.
For file operations I tend to think of it like the pointer is between indexes. It is kind of an in limbo indicator. What to expect from the future. This also relate to SEEK_END
as one can think of it of what one want to do in the future.
SEEK_END -3
- Now I can read last 3 bytes.SEEK_END 0
- No more bytes. Now I can append bytes.If offset is for example 4
then I know next byte is at index 4
and last read byte was at index 3
.
0 1 2 3 4 5 6 7 Offset
+---+---+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | Index
+---+---+---+---+---+---+---+
| | |
| | +--- Next Index
| +----- Offset 4
+------- Last Index
Some might find it awkward, but works for me.
As for SEEK_END
it is in the name. Seek relative to END. END is all read, indicating there is nothing left. The SEEK_END
and SEEK_SET
also have a direct relation as:
SEEK_SET - SIZE = SEEK_END
SEEK_END + SIZE = SEEK_SET
SEEK_SET - SEEK_END = SIZE
SEEK_SET + abs(SEEK_END) = SIZE
In the final diagram we have OFFSET
and ORIGIN
as arguments for seek()
.
(Size: 7 bytes) ,-- END of FILE
/
0 1 2 3 4 5 6 | O O | BYTES |
+---+---+---+---+---+---+---+ F R | L | R |
| A | B | C | D | E | F | G | F I | E | E |
+---+---+---+---+---+---+---+ S G | F | A |
| | | | E I | T | D |
| | | | T N . . RELATION
| | | | . . . .
| | | +-- 7, SEEK_SET | 0 | 7 | 7 - 7 = 0
| | | +-+ 0, SEEK_END | 0 | 7 | 0 + 7 = 7
| | | | 7 - -0 = 7
| | | |
| | +-----| 6, SEEK_SET | 1 | 6 | 6 - 7 = -1
| | +-----+ -1, SEEK_END | 1 | 6 | -1 + 7 = 6
| | | 6 - -1 = 7
| | |
| +-------------| 4, SEEK_SET | 3 | 4 | 4 - 7 = -3
| +-------------+ -3, SEEK_END | 3 | 4 | -3 + 7 = 4
| | 4 - -3 = 7
| |
+-----------------------------| 0, SEEK_SET | 7 | 0 | 0 - 7 = -7
+-----------------------------+ -7, SEEK_END | 7 | 0 | -7 + 7 = 0
| | 0 - -7 = 7
fseek(fh, offs, origin) |
/
ftell() -´
Upvotes: 2
Reputation: 4409
fseek allows appending texts to a current file. Therefore the filepointer is set after (!) the last character in the file, because that is the place where new characters are to be appended.
From the start:
01234 <---position
ABCDEFGHIJK <---file content
From the end:
43210 <---position
ABCDEFGHIJK <---file content
So when you are fetching from the start, the 0th character is the A And the 3rd is D.
But when you are fetching from the end, the 0th characters is EndOfFile And the -3rd is I.
Upvotes: 3
Reputation: 16213
I think is because of the last character of file is '\n'
or '\0'
or something like that.
Upvotes: -3
Reputation: 98348
SEEK_END
searches from the one-past last byte of the file:
1234567890 <--- bytes from the file
0123456789A <--- SEEK_SET-relative position
A9876543210 <--- SEEK_END-relative position (absolute value)
^
This is the (0, SEEK_END) byte
With this in mind, the very last byte of the file is the one found at (-1, SEEK_END)
and thus the (-3, SEEK_END)
byte is the 8
.
Note that this is consistent with how C usually handles this kind of thing. For example a pointer to the end of a memory block will usually point to one-past the last byte of that block.
This also has the nice feature that you can get the size of the file with a call to fseek(SEEK_END)
plus ftell
(). No need to add or substract 1
!
The man page from fseek()
is a bit ambiguous about this issue, but compare with the man lseek
that contains the same issue:
If whence is SEEK_END, the file offset shall be set to the size of the file plus offset.
In your example the size of the file is 10, and the offset is -3, so the final position is 10-3 = 7
. And in offset 7 there is an 8
.
Upvotes: 19