我在Windows上遇到一些文件写入失败的问题。我将其简化为以下示例:
FILE* f = fopen("test.out", "r+b");
fseek(f, -1, SEEK_END); // one byte before the end
printf("read byte: %cn", fgetc(f)); // read the last byte; now at the end
printf("attempting write: %dn", fputs("text", f));
正确输出test.out
的最后一个字节,但fputs
失败并返回-1。这些类似的例子都很好:
不读
FILE* f = fopen("test.out", "r+b"); fseek(f, 0, SEEK_END); // this is where I ended up after the fgetc() above printf("attempting write: %dn", fputs("text", f));
读取结束后查找(即使我们已经在那里)
FILE* f = fopen("test.out", "r+b"); fseek(f, -1, SEEK_END); printf("read byte: %cn", fgetc(f)); fseek(f, 0, SEEK_END); printf("attempting write: %dn", fputs("text", f));
寻找我们已经到达的确切位置
FILE* f = fopen("test.out", "r+b"); fseek(f, -1, SEEK_END); printf("read byte: %cn", fgetc(f)); fseek(f, ftell(f), SEEK_SET); printf("attempting write: %dn", fputs("text", f));
读取,但不是最后一个字节
FILE* f = fopen("test.out", "r+b"); fseek(f, -2, SEEK_END); // two bytes before the end printf("read byte: %cn", fgetc(f)); // read the penultimate byte printf("attempting write: %dn", fputs("text", f));
读取超过结束(…)
FILE* f = fopen("test.out", "r+b"); fseek(f, -1, SEEK_END); // one byte before the end printf("read byte: %cn", fgetc(f)); // read the last byte; now at the end printf("read byte: %cn", fgetc(f)); // read a garbage byte printf("attempting write: %dn", fputs("text", f));
这些似乎都表示流错误或eof问题,但ferror(f)
和feof(f)
都返回0,直到失败的fputs()
。之后,ferror(f)
是非零,但errno
是0,所以我不知道问题是什么
我只在Windows上看到这个,在Visual Studio 2008和GCC 4.7.2 (MinGW)中。在Linux上同样的代码运行没有错误
C标准要求在从"读模式"切换到"写模式"或反之亦然时执行seek,除非在某些通常不值得枚举的特殊情况之后。
一个实现(比如我几年前为bsd编写的那个,或者Linux的那个)可以比需要的更宽容,使你的代码"正常工作"。(这真的很简单,您只需要在实现中保留两个单独的计数器,而不是一个合并的计数器。)但是标准并不要求实现是友好的,Windows的也不是。