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

来源:互联网 发布:守望先锋淘宝 编辑:程序博客网 时间:2024/05/14 17:46

很多时候,我们用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,问题解决,写完。


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 阳台做防水了又贴砖还漏水怎么办 洗菜盆里的盖子吸住拔不起来怎么办 掉小区阴井盖里物业不管怎么办 卫生间下水道被头发堵了怎么办妙招 久量时尚夜光台灯不亮了怎么办 我想做水电暖工程没有资质怎么办 修手机被弄丢了没有开维修单怎么办 手机去维修被老板弄丢了怎么办 5年保修期过后房子楼顶漏水怎么办 墙内水管漏水怎么办3步骤巧维修 下面有地暖下面水管漏水怎么办 热水器接的塑料水管子漏水怎么办 电热水器烧热水时热水管漏水怎么办 户户通位置锁定模块异常1怎么办 户户通位置锁定模块异常3怎么办 逆战安全系统检测客户端异常怎么办 电视户户通位置信息模块异常怎么办 苹果手机wi-fi模块坏了怎么办 xp本地连接受限制或无连接怎么办 公司没帮二级建造师延续注册怎么办 考造价师考过了年限不够怎么办? 上海众非称重不显示数字怎么办 宝骏630防火墙隔热棉掉了怎么办 冷车启动水温报警灯亮了怎么办 租铺位面积比合同面积小怎么办 农村村民建房领居不肯签名怎么办 车祸死者家属不来协商赔偿怎么办 26岁想回去当老师了怎么办 面包车排量小空调带不凉快怎么办 科三包过不给退钱人跑了怎么办 护师职称考试成绩单丢了怎么办 河南二级建造师报名地址填错怎么办 山东以前的企业没有消防备案怎么办 重庆渝北初级审核时间过了怎么办 初级职称复核毕业证弄丢了怎么办 杭州公租房选房后变更单位的怎么办 契税交了贷款办不下来怎么办 天津公租房住满5年后怎么办 大江里钓鱼水流太急立不住漂怎么办 房子定金交了不想要了怎么办 房子付了首付不想要了怎么办