behaviour of fseek and SEEK_END
Asked Answered
S

4

6

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.

Starrstarred answered 18/12, 2014 at 15:11 Comment(2)
BTW, don't you have to use negative values for SEEK_END? (just asking, I don't know)Flail
...and I edited my answer accordingly.Flail
F
16

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.

Flail answered 18/12, 2014 at 15:14 Comment(0)
T
3

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.

Teodor answered 28/9, 2019 at 9:8 Comment(0)
U
0

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() -´
Unmoral answered 10/11, 2023 at 12:15 Comment(0)
M
-3

I think is because of the last character of file is '\n' or '\0' or something like that.

Murguia answered 18/12, 2014 at 15:16 Comment(2)
In this file there is not a '\n'.Starrstarred
This is so that when you seek exactly to the end (offset 0) - when you try to read, there's nothing left to read and when you start to write, you'll append.Habitant

© 2022 - 2024 — McMap. All rights reserved.