【Q&A】getline读取文本文件的问题

很多时候,我们用getline函数读取文本文件的每一行,留待以后进行处理(如:用istringstream对象解析行中的内容),代码片段如下:

ifstream in ("Test.txt");

if (!in)

return ;

string sLine;

while (getline (in, sLine))

// do something......

不过最近在处理一个文本的时候,发现getline读取到文件中间的某一行,就返回false了。不能读取完整个文件。我到文本文件的那一行用UE去看,发现很多乱码,显示如下:

&_N??/f?:N?l??JT???I{?_ @b???*N?NMbOUS@w0

debug进入到getline函数内部,看到代码如下:

const typename _Traits::int_type _Metadelim =
_Traits::to_int_type(_Delim);
typename _Traits::int_type _Meta = _Istr.rdbuf()->sgetc();


for (; ; _Meta = _Istr.rdbuf()->snextc())
if (_Traits::eq_int_type(_Traits::eof(), _Meta))
{ // end of file, quit
_State |= ios_base::eofbit;
break;
}
else if (_Traits::eq_int_type(_Meta, _Metadelim))
{ // got a delimiter, discard it and quit
_Changed = true;
_Istr.rdbuf()->sbumpc();
break;
}
else if (_Str.max_size() <= _Str.size())
{ // string too large, quit
_State |= ios_base::failbit;
break;
}
else
{ // got a character, add it to string
_Str += _Traits::to_char_type(_Meta);
_Changed = true;
}
_CATCH_IO_(_Istr)
}

代码逻辑很简单,就是一个for循环,不断读取字符,并做判断,分以下四种情况:

1. 遇到文件结尾(end of file),设置状态为ios_base::eofbit后返回

2. 遇到分隔符(delimiter),丢弃掉分隔符,并break出循环

3. 当字符串太大,无法存储,设置状态ios_base::failbit后返回

4. 否则,将字符attach到字符串尾部,继续循环。


debug发现,getline是在情况1的时候退出的,就是遇到了文件尾。


接下来的问题,文件尾是什么?上网上看了下,文本文件没有一个特定的字符来表示文件末尾,不像c字符串用'\0'来表示文件尾。文件尾字符的存在没有必要,因为文件对象已经记录了文件的大小。在读取的时候,随时判断是否达到了文件的大小;如果达到了,就返回EOF。EOF在VS中用宏在stdio.h中定义为-1,代码如下:


#define EOF     (-1)


上面代码中_Traits::eof()就是返回EOF的值。


分析原因,是在文本文件流中有一个字符的值是-1(实际值是255,对应blank 'FF',在linux的terminal中,ctrl+D能够在流中插入文件尾,表示用户结束屏幕输入),这个字符被正常独取出来,而读取的总字符数也没有达到文件大小,但是getline在这个字符和EOF比较中,发现两者相等,就认为读取到了文件尾,就结束读取,设置流的相关状态,blablalblaa...,以后的都知道了。


那么这个问题如何解?网上给了一个方法:用二进制形式读取。因为对于文本文件,-1意味着文件尾;而对于二进制文件,-1并不是文件尾。而且,看getline源代码,可以在二进制模式下工作。


修正上面的读取代码为:

ifstream in ("Test.txt", ios_base::binary);

if (!in)

return ;

string sLine;

while (getline (in, sLine))

// do something......


读取成功,问题解决。


接下来,我又将读取的内容写到文本文件中,代码如下:

ifstream in ("Test.txt", ios_base::binary);

ofstream out ("Test2.txt")

if (!in || !out)

return ;

string sLine;

while (getline (in, sLine))

out << sLine <<"\n";


用文本文件方式读取,依然出问题;用二进制ios_base::binary读取,依然没问题,呵呵。看来输出流是把输入流(无论是文本形式还是二进制形式)中的内容原原本本地写到文件中了,这中间没有任何过滤行为。


OK,问题解决,写完。


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值