C语言中在putw操作后调用fread为什么会导致文件体积变大?
问题现象
我尝试使用fread()从文件读取数据时,发现文件体积一直在持续增长,该行为不符合读取场景的预期。我编写了如下测试代码复现问题:使用putw()向文件写入数据后,不关闭重新打开的文件就直接读取时,fread会为了完成读取操作扩大文件体积。
测试环境
- 操作系统:Windows 8.1
- 编译器:MinGW gcc
测试代码
typedef struct { int a; int b; } A; int main() { FILE* f = fopen("file", "wb"); A a; a.a = 2; a.b = 3; putw(1, f); fwrite(&a, sizeof(A), 1, f); fclose(f); // 排除wb模式和fwrite导致该问题的可能性 f = fopen("file", "rb+"); printf("initial position: %ld\n", ftell(f)); putw(1, f); printf("position after putw: %ld\n", ftell(f)); printf("fread result: %d\n", fread(&a, sizeof(A), 1, f)); printf("position after 1st fread: %ld\n", ftell(f)); printf("fread result: %d\n", fread(&a, sizeof(A), 1, f)); printf("position after 2nd fread: %ld\n", ftell(f)); fclose(f); remove("file"); return 0; }
运行结果
initial position: 0 position after putw: 4 fread result: 1 position after 1st fread: 12 fread result: 1 position after 2nd fread: 20
问题原因
这是因为你违反了C标准中对带+的更新模式文件流的操作规则:
C11标准7.21.5.3第7段明确规定:当以更新模式打开文件时,流上可以同时执行输入和输出操作。但输出操作后不能直接跟随输入操作,输入操作后也不能直接跟随输出操作,除非满足以下两个条件之一:
- 中间执行了
fflush刷新输出缓冲区,或执行了fseek/fsetpos/rewind等文件定位操作- 输入操作遇到了文件结束符
你的代码在rb+模式的流上执行完putw(输出操作)后,没有进行任何刷新或定位操作就直接调用fread(输入操作),属于未定义行为。你观测到的文件自动扩大,是MinGW运行库对该未定义行为的具体实现表现。
修复方案
在putw操作完成后、第一次fread调用前,添加文件定位操作即可,比如你需要从当前指针位置(偏移量4)开始读取,可以添加:
fseek(f, ftell(f), SEEK_SET);
修复后第二次fread会返回0(表示已读到文件末尾,无更多数据),也不会出现文件体积异常扩大的问题。
内容的提问来源于stack exchange,提问作者Navid Naseri
相关产品推荐
相关产品推荐

