为什么POSIX允许在只读模式下通过fseek寻址超出现有文件结尾?

3
为什么查找文件末尾可以很有用?为什么POSIX允许在只读文件中进行示例中的查找?
c++: http://en.cppreference.com/w/c/io/fseek posix: https://www.unix.com/man-page/posix/3P/fseek/ 我在MinGW-64上测试了下面的代码。
#include <cassert>
#include <cstdio>
#include <cstring>

int main() {
  std::FILE* f = std::fopen("tmp_file.txt", "wb");
  auto result = std::fwrite("1", 1, 1, f);
  assert(result == 1);
  result = std::fclose(f);
  assert(result == 0);

  f = std::fopen("tmp_file.txt", "rb");  // READ ONLY binary mode
  result = std::fseek(f, 100500, SEEK_SET);
  assert(result == 0);  // WHY I can seek to not existing position in file?
                        // opended in READ_ONLY mode?
  char buff[100500] = {0};
  result = std::fread(&buff, sizeof(buff), 1, f);
  printf("result = %zu, errno: %s ferror(f): %d feof(f): %d", result,
         std::strerror(errno), std::ferror(f), std::feof(f) != 0);

  return result;
}

1
你的问题和代码似乎是关于C++的,而你的链接是C资源。C和C++是不同的语言,你应该选择其中一种。 - ad absurdum
fseek() 的更正确的 POSIX 链接应该是 http://pubs.opengroup.org/onlinepubs/9699919799/functions/fseek.html。 - Andrew Henle
1
可能是历史先例的结合(Unix允许它)和没有特别的理由禁止它。 - Jonathan Leffler
@DavidBowling C和C++是不同的语言,你应该选择其中一种。 在这种情况下,- C标准IO - C++基本上是依赖于C的。虽然在这种情况下,我认为它并不重要 - 我认为“为什么”要么完全无法知道,要么是基于个人观点的。 - Andrew Henle
@AndrewHenle -- 已经注意到了。 - ad absurdum
printf("result = %zu,... 的输出中追加 post code,并且您的期望会增加问题的清晰度。(另外:有趣的代码没有使用 std::printf - chux - Reinstate Monica
2个回答

7
“为什么寻找文件末尾会有用?” 通常情况下,这取决于实现方式。C和C++并没有规定此类操作必须成功,尽管POSIX规范要求如此,您似乎已经知道了。即使在非POSIX C中, 如果在“fseek”内部发生读取或写入错误,则会设置流的错误指示器,并且“fseek”将失败(参见C2011 7.21.9.2/2)。此外,对“fseek”函数的成功调用会撤消流上“ungetc”函数的任何效果,并清除流的文件结束标志。

(C2011 7.21.9.2/5). 即使fseek将文件定位在奇怪但有效的状态下,这些副作用可能是有意义的。尽管如此,您的问题

为什么POSIX允许在只读文件中进行类似示例的查找?

表明您认为如果fseek将(只读)文件定位到无法读取数据的位置,它应该失败。但为什么要为此制定特殊规定呢?根据POSIX,可同时进行读写的文件可以被定位在其末尾之后,然后读取它与读取类似定位的只读文件没有太大区别。

使fseek在所有可查找文件上的行为保持一致比您所认识到的更有价值。


6
如您所知,如果在可写文件的末尾之外寻求并写入,则会扩展该文件。我猜您的问题是,您不想扩展仅用于读取的文件,因为扩展是一种修改。
但是,仅仅寻求超出可写文件的末尾并不会扩展它——需要寻求然后写入。寻求只是设置读/写点。
因此,在读取时超出文件结尾进行寻求会设置读点,这只是数据结构中的一个数字,因此我想没有人会担心检查其有效性。如果您在可读文件的末尾之外进行寻求,然后尝试写入,则会收到错误消息(“文件未打开以进行写入”),如果您在可读文件的末尾之外进行寻求,然后读取,则只会得到EOF。在任何情况下,都不会扩展或以其他方式更改文件。
(您可能还想知道,如果您在另一个进程正在写入的可读文件的末尾之外进行寻求,然后该其他进程继续写入以“填充”到您寻求的位置,然后再次尝试读取会发生什么?那是个有趣的问题。我认为它会起作用,但我没有尝试过。)

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