我有一个用C编写的小例子程序。我有一个main调用一个函数writeFile
,它在二进制文件中写入一些数字。 然后我打电话overwrite
,用1代替0,最后打印结果。
这是代码:
#include <stdio.h> /* Print the content of the file */ void printFile(){ printf("Read test.dat:\n"); int r; FILE* fp = fopen("test.dat", "rb+"); if(fp) { while(fread(&r,sizeof(int),1,fp)){ printf("%d\n", r); } } fclose(fp); } /* Replace 0 with 1 */ void overwrite(){ int r; FILE *fp = fopen("test.dat", "rb+"); if (fp) { int i=0; while (i < 4 && fread(&r, sizeof(int), 1, fp)) { i++; if (r == 0) { r = 1; fseek(fp,-sizeof(int),SEEK_CUR); fwrite(&r,sizeof(int),1,fp); } } } fclose(fp); } /* Create original file */ void writeFile() { int b, b1, b2, b3, b4; b = 3; b1 = 2; b2 = 0; b3 = 4; FILE *fp = fopen("test.dat", "wb"); if (fp) { fwrite(&b, sizeof(int), 1, fp); fwrite(&b1, sizeof(int), 1, fp); fwrite(&b2, sizeof(int), 1, fp); fwrite(&b3, sizeof(int), 1, fp); } fclose(fp); } int main() { writeFile(); printf("---------BEFORE--------\n"); printFile(); printf("-----------------------\n"); printf("Overwriting...\n"); overwrite(); printf("---------AFTER---------\n"); printFile(); return 0; }
这段代码适用于Linux,但是当我在Windows上运行相同的代码时,输出是这样的:
---------BEFORE-------- Read test.dat: 3 2 0 4 ----------------------- Overwriting... ---------AFTER--------- Read test.dat: 3 2 1 2
不仅0被1代替,而且最后的数字也被改变了。 有人可以帮助我理解为什么发生这种情况?
另一个问题是,在overwrite
我必须使用i
停止,因为没有i<4
我得到一个无限循环(只有Windows)。
我使用gcc 4.8.1(从MinGW)编译的Windows 8.1上testing了这个代码。 在我的Linux机器上,我用gcc 5.1.1testing了代码。
谢谢你们,
这是因为你需要在fwrite()
fflush()
之后使用fflush()
,因为在不调用fflush()
调用之后,不应该调用fwrite()
调用fread()
这是与这种情况相关的标准部分
7.21.5.3
fopen
函数
- 当以更新模式打开文件(在上述模式参数值列表中,第二个或第三个字符为
'+'
)时,输入和输出都可以在关联的流上执行。 然而,输出不应该直接跟随输入,而不需要中间调用fflush
函数或文件定位函数(fseek
,fsetpos
或rewind
),并且输入不应该直接跟在输出之外,而不需要中间调用文件定位函数,除非输入操作遇到文件结束。 在某些实现中打开(或创建)具有更新模式的文本文件可能会打开(或创建)二进制流。
这个部分在fopen()
函数中很奇怪,因为它涉及fread()
和fwrite()
,这是我在寻找答案的地方。
你也可以看到,我以前的答案有效,但不是因为我在其中阐述的原因,而是在上面的段落中找到解释。
MSDN声明流I / O :
输入可以直接跟随输出直接使用中间调用
fflush
或文件定位功能(fseek
,fsetpos
或rewind
)。 如果输入操作遇到文件结尾,则输出可以跟随输入,而不需要对文件定位功能进行干预。
所以你必须在调用fwrite之后调用fflush()
:
void overwrite() { FILE *fp = fopen("test.dat", "rb+"); if (fp) { int r; while (fread(&r, sizeof(int), 1, fp) == 1) { if (r == 0) { r = 1; fseek(fp,-sizeof(int),SEEK_CUR); fwrite(&r,sizeof(int),1,fp); fflush(fp); /* Flush here */ } } fclose(fp); /* Also: call fclose() only when fopen() succeeded */ } }