使用 fgets() 读取一个文本文件的时候,如果读取的 方法不恰当,就有可能造成重复读取最后一行的问题。具体如下。
(1) 在 Windows 平台上, 假设有 test.txt ,内容如下:
this is line 1 this is line 2 this is line 3 this is line 4
while( ! feof(fp) ) { char tmp[100] ; fgets( tmp , 100 , fp ); cout<<tmp<<endl; }
然而,换成 Linux 平台,就有不同的运行结果,如下:
(2)我们使用另一种读取方法:
/* 改进的读取txt文件的方式 */ while( true ) { char tmp[100]; fgets( tmp , 100 , fp ); if( feof(fp) ) break; cout<<tmp<<endl; }
很明显,最后一行没有被读取。
换成 Linux 平台,再次执行,结果如下:
(3) 现象原因分析
引用网上大牛的解释:
feof是ANSI标准定义的:在遇到文件结束时返回非0值。
对于象DOS系统,这比较方便。因为文件有明确的结束标志EOF。
对于UNIX,就稍微麻烦一点。因为文件没有结束标志,只有通过当前指针和文件长度来判断文件是否结束。当 read 时,先调用trap进入核心态,由FILE->;ile->;inode,取得文件的物理地址,然后取得文件的剩余的长度,比较该长度是否为0,如果为0则置文件结束标志;如果不为0,则比较该长度和要读的长度,取其中的小值,并将文件内容读入用户地址。
具体到我们所遇到的现象就比较清晰了,读文件最后一行的fgets(也是调用read的)被调用的时候,该文件的剩余长度不为0,所以不置文件结束标志。而再fgets时,文件的剩余长度为0,文件结束标志被置且马上返回。
(4)兼容 windows 和 Linux 的文件读取方式
分析了现象和原因,最后给出一种在Windows和Linux上都能够正确读取文本的方法。
/* 统一的的读取txt文件的方式 */ char tmp[100] ; while( fgets(tmp , 100 , fp ) != NULL ) { cout<<tmp<<endl; }
在 Linux 下,执行结果:
实验表明,这种读取方法在两种平台都能正确地读取。