我有一个用C编写的小例子程序。我有一个调用函数writeFile
的函数,它在二进制文件中写入一些数字。然后我调用overwrite
将0替换为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上测试了此代码。 在我的Linux机器上,我用gcc 5.1.1测试了代码。
谢谢大家,
答案 0 :(得分:7)
这是因为您需要在fflush()
之后fwrite()
,因为在拨打fread()
之后,如果没有对fwrite()
进行干预,则不应致电fflush()
,< / p>
这是与此案例相关的标准部分
7.21.5.3
fopen
功能
- 当使用更新模式(
醇>'+'
作为上述模式参数值列表中的第二个或第三个字符)打开文件时,可以在关联的流上执行输入和输出。但是,如果没有输入,输出不应直接输入 干预对fflush
函数或文件定位函数(fseek
,fsetpos
或rewind
)的调用,输入不应直接跟随输出而不是 干预调用文件定位功能,除非输入操作遇到文件结束。在某些实现中,打开(或创建)具有更新模式的文本文件可以改为打开(或创建)二进制流。
这部分属于fopen()
函数,这很奇怪,因为它涉及fread()
和fwrite()
,这是我在寻找答案的地方。
您还可以看到我的http://jsfiddle.net/t68ajjnv/8/有效,但不是因为我在其中说明的原因,而是在上面的段落中找到了解释。
答案 1 :(得分:2)
Stream I/O的MSDN状态:
输入只能通过对
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 */
}
}