问题
讲一个书上提到的关于文件结束符处理的小问题,之前没有注意过这个点。
问题也很简单:从一组文件里面读取数字并求和。
//scores.txt 注意:5后面有一个空格
1 2 3 4 5
考虑如下代码实现:
#include <iostream>
#include <fstream>
int main( void )
{
std::ifstream fin;
fin.open( "scores.txt" );
if( !fin.is_open() )
{
std::cerr << "Can not open the file!" << std::endl;
return -1;
}
int val = 0;
int sum = 0;
while( !fin.eof() )
{
fin >> val;
sum += val;
}
std::cout << "Total is " << sum << std::endl;
fin.close();
return 0;
}
思路
程序应该输出15,但是却输出了20。这是什么原因?并且程序的逻辑看起来是没有错误的。
但是对于输入文件而言,如果删除掉5后面的空格。发现程序正确。
所以,问题可能就出在5后面的空格上面。因为,当5读取结束之后,此时,文件是没有到结束符的。还是会继续读取,但是由于读取空格到整型变量val中会出现问题,所以fin的状态会失效。并不会覆盖之前的val值。所以,又被累加了一遍,这才得到20。
所以,如果要用eof来判断文件是否结束,应该避免文件的结束符是诸如空格这样的字符。
虽然文件没有读取完毕,但是这并不是有效的输入。这点注意。
对于上面问题的修正,可以采取如下的方法:
#include <iostream>
#include <fstream>
int main( void )
{
std::ifstream fin;
fin.open( "scores.txt" );
if( !fin.is_open() )
{
std::cerr << "Can not open the file!" << std::endl;
return -1;
}
int val = 0;
int sum = 0;
while( !fin.eof() )
{
fin >> val;
if( fin ) // 判断一下是否正确读取
{
sum += val;
}
}
std::cout << "Total is " << sum << std::endl;
fin.close();
return 0;
}
或者,由于fin对象在读取到非数字的变量时会返回NULL。也就是说可以用fin >> val来当做文件读取结束的条件。因为,如果没有这个空格。当fin读取到eof的时候,还是会返回NULL。从而可以判断循环结束。
#include <iostream>
#include <fstream>
int main( void )
{
std::ifstream fin;
fin.open( "scores.txt" );
if( !fin.is_open() )
{
std::cerr << "Can not open the file!" << std::endl;
return -1;
}
int val = 0;
int sum = 0;
while( fin >> val )
{
sum += val;
}
std::cout << "Total is " << sum << std::endl;
fin.close();
return 0;
}
再或者,可以先把整个文件结尾的空白符都处理掉,然后使用第一种办法也是可以的。