关于ifstream的读取末尾判断问题

wu_chung_tang 2006-10-12 01:54:25
关于ifstream的读取末尾判断问题

我先用写一个文件

struct MyStruct;
MyStruct s;

std: fstream of("kkk.txt");
of.write((char *)(&s), sizeof(MyStruct));
of.close();

打开文件一看确实有了一份data 然后再读

std::ifstream if("kkk.txt");
while(!if.eof())
{
if.read((char *)(&s), sizeof(MyStruct));
}
if.close();

却读了两遍 重读了一遍 为何第一遍读完后eof()仍然返回true?

我用VC++ 7.0 2002
...全文
1631 16 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
roger_77 2006-10-14
  • 打赏
  • 举报
回复
其实最后那个数据并没有读取了两次,
只在用(!from.eof())来判断时,如果读取到了文件的数据末尾,但还没到文件的结束标识EOF,
再读取sizeof(buf))大小的数据时,fstean流的状态会标识为失败,但buf中的值没有被改变,还是保存了上一次读取的数据。

可以用下面的方法验证:

while(!from.eof())
{
from.read((char*)(&buf), sizeof(buf));
std::cout << buf << endl;//最后一次会输出0
buf = 0;
}


///////////////////////////////////////////////////////////
所以读取文件数据时,一般可以考虑使用 from.eof()与from.fail()结合来判断。
roger_77 2006-10-14
  • 打赏
  • 举报
回复

楼主可以参考一下,下面的几种读取方式都不会楼主的情况,即最后一个数据重复读取了两次?

代码:

#include <fstream>
#include <iostream>
#include <string>

using namespace std;


int main(int argc, char* argv[])
{
const int bufSize = 256;
string s="test.dat";


ofstream to(s.c_str());
if(!to)
cout << "cannot open the file:" << s << std::endl;

for(int i=1;i< 10; ++i)
{
to.write((char*)&i, sizeof(i));
}

to.close();

ifstream from(s.c_str());
if(!from)
cout<<"cannot open the file:"<<s<<endl;

int buf =0;
while(from.read((char*)(&buf), sizeof(buf)))//(!from.eof())
{
std::cout << buf << endl;
}
from.clear();
from.seekg(ios::beg);
std::cout << "while(!from.eof())+from.fail()" << endl;
while(!from.eof())
{
from.read((char*)(&buf), sizeof(buf));
//文件的数据末尾,但还没到文件的结束标识,
//再读取sizeof(buf))大小的数据会失败,但buf中的值没有被改变,还是上一次读取的数据
if (from.fail())
{
break;
}
std::cout << buf << endl;
}
from.clear();
from.seekg(ios::beg);
std::cout << "while(true)+from.fail()" << endl;
while(true)
{
from.read((char*)(&buf), sizeof(buf));
if (from.fail()) //
{
break;
}
std::cout << buf << endl;
}

system("pause");
return 0;
}

fangrk 2006-10-14
  • 打赏
  • 举报
回复
#include <fstream>
#include <iostream>
using namespace std;
struct MyStruct
{
int a;
char b;
float c;
};
int main()
{
MyStruct s;

ofstream ofs("kkk.txt",ios::binary);
ofs.write((char *)(&s), sizeof(MyStruct));
ofs.close();


ifstream ifs("kkk.txt",ios::binary);
int count=0;
while(ifs.read((char *)(&s), sizeof(MyStruct)))
{
cout<<"read "<<++count<<'\n';
}

}


D:\TEMP>d

D:\TEMP>cl /GX d.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86
Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.

d.cpp
Microsoft (R) Incremental Linker Version 7.10.3077
Copyright (C) Microsoft Corporation. All rights reserved.

/out:d.exe
d.obj

D:\TEMP>d
read 1

D:\TEMP>
fangrk 2006-10-14
  • 打赏
  • 举报
回复
while(if.read((char *)(&s), sizeof(MyStruct)))
{

}
jixingzhong 2006-10-14
  • 打赏
  • 举报
回复
需要说明的是:

继续读取,标志正常,读取内容(这个读取是非预期的),出错,标志置位,

这个过程由于出错了,
所以你原来的读取缓存中内容没有改变,
而不是说再读了一次这个内容,
它只是上一次读取的内容,在本次操作没有新的数据而残留下来的。
jixingzhong 2006-10-14
  • 打赏
  • 举报
回复
请仔细分析其过程:
while(!if.eof())
{
if.read((char *)(&s), sizeof(MyStruct));
}

eof 是根据流的标志来操作的。
在文件末尾处,标志正常,读取内容,正常,标志不变; //这里是正常过程
继续读取,标志正常,读取内容(这个读取是非预期的),出错,标志置位,
下一次读取时候,标志置位了, 读取终止。

从这个过程看,
很明显在最后一个读取时候, 会有一个重复操作,
事实上这个也常见的问题之一。

修正的方法是:
不要根据流标志处理, 而是根据读取的内容判断是否还要进行下一次读取操作,
这样,在发生错误的时候,读取马上就会被终止了,
而不会发生滞留。
希望之晨 2006-10-14
  • 打赏
  • 举报
回复
不错,我验证了...
while(!if.eof())
{
if.read((char *)(&s), sizeof(MyStruct));
if (if.fail()) //
{
break;
}
//do your job....
}
if.close();
OOPhaisky 2006-10-13
  • 打赏
  • 举报
回复
同意sinall() 的说法^_^
希望之晨 2006-10-13
  • 打赏
  • 举报
回复
while(if) while(!if.eof())
我测试了下,好像都会多读入一次..Mark
taodm 2006-10-13
  • 打赏
  • 举报
回复
wanfustudio(雁南飞)的回答完全正确!
这个题,你最好重载MyStruct的输入流运算符,这样就没有这个eof问题了。
而且,还将可以使用更简洁的istream_iterator来完成循环。
lvbdj 2006-10-13
  • 打赏
  • 举报
回复
顶一个。。。
weijiangshanwww 2006-10-12
  • 打赏
  • 举报
回复


成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();
可能的原因:
while(!if.eof())
{
if.read((char *)(&s), sizeof(MyStruct));
}
if.close();
===========
其中的sizeof(MuStruct)太小,读的部分还没到文件的末尾,所以判断还是真,然后又读了一遍。
飞哥 2006-10-12
  • 打赏
  • 举报
回复

feof( )没有问题
当你的文件指针到达文件末尾时
执行feof不会返回 1
要到下一次读取才会返回。

在读取最后一个之后,
虽然到了末尾
但是feof(fp)还是返回0
直到ch=fgetc(fp); //文件结束后再读了一次
然后的feof才返回
飞哥 2006-10-12
  • 打赏
  • 举报
回复
1。结构体就好用2进制读写
2。最好不用feof判断文件结束:读失败feof检查不出来
判断fread的返回值
sinall 2006-10-12
  • 打赏
  • 举报
回复
我的经验是:

while(if)
{
if (if.read((char *)(&s), sizeof(MyStruct)))
{
// 处理你的MyStruct对象
}
}
sinall 2006-10-12
  • 打赏
  • 举报
回复
while(if)
{
if.read((char *)(&s), sizeof(MyStruct));
}

65,195

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧