fseek和SEEK_END的行为

5
如果我有一个文本文件,其内容如下所示,并以二进制方式打开
1234567890

像这样的调用:

fseek(fp, 5L, SEEK_SET);

当我调用(char)fgetc(fp)时,给我返回的是第6个byte,因为我从byte 0开始(不是从1开始而是从2开始),所以需要偏移5个byte。

但如果我这样做:

fseek(fp, -3L, SEEK_END);

当我调用(char)fgetc(fp)时,请给我8而不是7。

为什么?由于使用了SEEK_END,偏移量似乎不从最后一个字节之后的上一个字节开始。


1
顺便问一下,SEEK_END 不是要使用负值吗?(只是问问,我不确定) - rodrigo
哦,是的!我编辑了我的帖子。 - xdevel2000
...然后我相应地编辑了我的答案。 - rodrigo
4个回答

13

SEEK_END 搜索文件最后一个字节的下一个位置:

1234567890   <--- bytes from the file
0123456789A  <--- SEEK_SET-relative position
A9876543210  <--- SEEK_END-relative position (absolute value)
          ^
          This is the (0, SEEK_END) byte
考虑到这一点,文件的最后一个字节是在(-1, SEEK_END)找到的,因此(-3, SEEK_END)字节是8
请注意,这与C通常处理此类事情的方式是一致的。例如,指向内存块末尾的指针通常会指向该块的最后一个字节的下一个字节。
这也有一个很好的特性,你可以通过调用fseek(SEEK_END)加上ftell()来获取文件的大小。不需要添加或减去1
fseek()的man页面对此问题有些模棱两可,但与包含相同问题的man lseek进行比较:

如果whence是SEEK_END,则文件偏移量将设置为文件大小加上偏移量。

在你的例子中,文件的大小为10,偏移量为-3,因此最终位置为10-3=7。在偏移量7处有一个8

2

fseek允许将文本附加到当前文件。因此,文件指针设置在文件中最后一个字符之后,因为这是追加新字符的位置。

从头开始:

01234         <---position
ABCDEFGHIJK   <---file content

从最后开始:

       43210  <---position
ABCDEFGHIJK   <---file content

当你从开头获取时,第0个字符是A,第3个字符是D。

但当你从结尾获取时,第0个字符是EndOfFile,第-3个字符是I。


0
这一切都归结于可视化。
我把文件看作一个以零为基准的数组。即,索引为0的字节等等。
对于文件操作,我倾向于将指针看作位于索引之间。它是一种处于中间状态的指示器,预示着未来的期望。这也与SEEK_END有关,可以将其视为对未来的期望。
  • SEEK_END -3 - 现在我可以读取最后3个字节。
  • SEEK_END 0 - 没有更多字节了。现在我可以追加字节。
  • ...
如果偏移量例如为4,那么我知道下一个字节位于索引4,上次读取的字节位于索引3
0   1   2   3   4   5   6   7  Offset
+---+---+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 | 5 | 6 |  Index
+---+---+---+---+---+---+---+
              | | |
              | | +--- Next Index
              | +----- Offset 4
              +------- Last Index

有些人可能觉得这有点尴尬,但对我来说很有效。
至于SEEK_END,它的名字已经说明了一切。相对于末尾进行查找。末尾已经全部读取,表示没有剩余内容。而SEEK_ENDSEEK_SET也有直接的关系,如下所示:
SEEK_SET - SIZE     = SEEK_END
SEEK_END + SIZE     = SEEK_SET
SEEK_SET -     SEEK_END  = SIZE
SEEK_SET + abs(SEEK_END) = SIZE

在最后的图表中,我们将OFFSETORIGIN作为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() -´

-3

我认为这是由于文件的最后一个字符是'\n''\0'或类似的东西造成的。


在这个文件中没有 '\n'。 - xdevel2000
这样做是为了当您精确地寻找到末尾(偏移量为0)时 - 当您尝试读取时,没有剩余内容可供阅读,而当您开始写入时,将会追加。 - user2224389

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接