今天凌晨无聊逛CSDN论坛的时候发现了这样一个帖子:
楼主使用fopen系列函数以“r+”的模式打开一个写有“abcdefg”字符串的文件,循环fgetc、printf,最后fclose,程序显示出“abcdefg”没有问题。但再次打开文件,先fputc(‘Z’, fp),然后循环fgetc、printf,最后fclose,这就出问题了。
问题表现为两个方面:一是printf出来的字符串不是预期的“bcdefg”,而是很多“屯”的字样;二是原文件也并不是预期的“Zbcdefg”,而是“Z屯屯屯…”。
经过调试分析,我的结论如下:fopen仅仅分配了相关资源如FILE *fp,但并没有及时地将文件流加载到内存缓冲区,并予以维护。内存缓冲区的分配与文件流的加载及维护被延迟到对文件流的第一次读或写操作时,如fgetc、fputc。大家可以想想为什么会这么做,这里我就不说明了。
回到楼主的问题:
第一次fopen——仅分配了部分资源。循环fgetc、printf——分配内存缓冲区、加载文件流并维护流的状态。这样,在fgetc时“abcdefg”文件流已经被正确地加载和维护,因此接下来循环对它进行读取并打印出来不会出现问题。
第二次fopen——仅分配了部分资源。fputc——问题出现在这,分配内存缓冲区(一个页面大小4k),写入字符“Z”。注意,这里并没有加载文件流,而仅仅是在分配的内存缓冲区上直接写入了字符“Z”,等到“必要的时候”系统会自动地刷新这种变化到硬盘上真正的文件中去。
很遗憾的是,在4K的内存缓冲区中仅仅写入了一个byte,系统并不觉得应该刷新,它在等待更多的写入操作,然后再刷新,保证效率。
因此这以后的循环fgetc、printf——是在操作没有真正从文件中加载文件流的内存缓冲区,除了写入了字符“Z”,剩下的部分(4K-1byte)都是未初始化的,显示出来就是“屯”的字样。
综上所述,楼主要解决问题的关键就是应该在fputc和循环fgetc、printf之前刷新缓冲区,如fflush,这样就能正确地加载并维护文件流了。
原帖地址:http://topic.csdn.net/u/20110506/20/adf1798c-3868-4085-89eb-36454ff3745a.html