在读取文件时查找文件结尾 [英] Finding end of file while reading from it
问题描述
void graph :: fillTable()
{
ifstream fin;
char X;
int slot = 0;
fin.open(data.txt);
while(fin.good()){
fin>> Gtable [slot] .Name;
fin>> Gtable [slot] .Out;
cout<<< Gtable [slot] .Name<< endl;
for(int i = 0; i <= Gtable [slot] .Out-1; i ++)
{
** //无法到达这里**
fin> ;X;
cout<< X<< endl;
Gtable [slot] .AdjacentOnes.addFront(X);
}
slot ++;
}
fin.close();
}
这是我的代码,基本上它确实是我想要的,阅读时文件不好了。它会输入和输出我正在寻找的所有东西,然后当文件结束时,fin.good()显然不返回false。这是文本文件。
A 2 BF
B 2 CG
C 1 H
H 2 GI
I 3 AGE
F 2 IE
这里是输出
A
B
F
B
C
G
C
H
H
G
I $ b b I
A
G
E
F
I
E
分段故障
-
这是Gtable的类型。
struct Gvertex:public slist
{
char Name;
int VisitNum;
int Out;
slist AdjacentOnes;
// slist的链表
};
我希望它在输出'E'后停止,'E'是文件中的最后一个字符。在读完最后一个字符后,程序不再进入for循环。解决方案你在while循环中的条件是错误的。
ios :: eof()
不是
predict;它只会在流试图
(内部)读取超出文件末尾时设置。您必须在每个
输入后检查。
处理您的案例的经典方法是定义
< / code>
函数GTable
,沿着以下行:std :: istream&
operator>>(std :: istream& source,GTable& dest)
{
std :: string line;
while(std :: getline(source,line)&& line.empty()){
}
if(source){
std :: istringstream tmp线);
std :: string name;
int count;
if(!(tmp>> name>> count)){
source.setstate(std :: ios :: failbit);
} else {
std :: vector< char> adjactentOnes;
char ch;
while(tmp>> ch){
adjactentOnes.push_back(ch);
}
if(!tmp.eof()|| adjactentOnes.size()!= count){
source.setstate(std :: ios :: failbit);
} else {
dest.Name = name;
dest.Out = count;
for(int i = 0; idest.AdjacentOnes.addFront(adjactentOnes [i]);
}
}
}
}
return source;
}
(这是写得相当仓促。
将内循环因素转换为单独的函数。)
注意:
-
我们逐行读取,以验证格式(并允许
在发生错误时重新同步)。 -
我们在输入错误时设置源流中的
failbit
。 -
空行(因为您的输入显然包含它们)。
-
我们不修改目标元素,直到我们确定输入
是正确的。
我们有这个,很容易循环所有元素:
int slot = 0;
while(slot< GTable.size()&& fin>> GTable [slot]){
++ slot;
}
if(slot!= GTable.size)
// ...错误...
编辑:
我会明确指出,因为其他人回应似乎
错过了:绝对必须确保您在尝试阅读之前中有
的地方。
编辑2:
鉴于此问题收到的错误答案的数量,我会
喜欢强调:
-
任何使用
fin.eof()
之前输入已知失败都是错误的。 -
在测试输入
成功之前读取的任何值的任何使用都是错误的。 (这不妨碍fin>> a>>
,只要
ba
或b
在成功之前使用
测试。) -
尝试读入
Gtable [slot]
,但不确保插槽
在边界是错误的。 / p>
关于 eof()
和 good()
:
istream的基类
$ c> ostream 定义三个
“错误位: failbit
, badbit
和 eofbit
。这是
重要的是要理解何时设置这些: badbit
设置在情况下的
不可恢复的硬错误(实际上从来没有,事实上,因为大多数
实现不能或不检测这样的错误);并且
中设置 failbit
任何其他情况下输入失败—无数据可用(
文件结束)或格式错误当输入int等时,c $ c>abc)。 随时设置 c> EOF ,无论这个
导致输入失败还是失败!因此,如果你读取一个 int
,并且
流包含123
或换行符,将设置
eofbit
(因为流必须提前读取,知道
int
ends);如果流包含123 \\\
,则不会设置 eofbit
。
但是,在这两种情况下,输入成功, failbit
将不会被
设置。
要读取这些位,有以下函数(作为代码,因为I
不知道如何获取表格否则):
eof():返回eofbit
bad():返回badbit
fail():返回failbit || badbit
good():returns!failbit&& !badbit&& !eofbit
operator!():返回fail()
operator void *():返回fail()? NULL:this
(通常---所有保证的是!fail()返回非null。)
b $ b
给定:第一个检查必须总是 fail()
或
运算符之一
(基于 fail
)。一旦 fail()
返回true,我们
可以使用其他函数来确定原因:
if(fin.bad()){
//严重的问题,磁盘读取错误等。
} else if(fin.eof()){
//文件结尾:没有数据要读。
} else {
//格式化错误:类似abc的int
}
实际上,任何其他使用都是错误的(和任何使用 good()
是一个错误—我为什么该功能存在)。
void graph::fillTable()
{
ifstream fin;
char X;
int slot=0;
fin.open("data.txt");
while(fin.good()){
fin>>Gtable[slot].Name;
fin>>Gtable[slot].Out;
cout<<Gtable[slot].Name<<endl;
for(int i=0; i<=Gtable[slot].Out-1;i++)
{
**//cant get here**
fin>>X;
cout<<X<<endl;
Gtable[slot].AdjacentOnes.addFront(X);
}
slot++;
}
fin.close();
}
That's my code, basically it does exactly what I want it to but it keeps reading when the file is not good anymore. It'll input and output all the things I'm looking for, and then when the file is at an end, fin.good() apparently isn't returning false. Here is the text file.
A 2 B F
B 2 C G
C 1 H
H 2 G I
I 3 A G E
F 2 I E
and here is the output
A
B
F
B
C
G
C
H
H
G
I
I
A
G
E
F
I
E
Segmentation fault
-
Here's is Gtable's type.
struct Gvertex:public slist
{
char Name;
int VisitNum;
int Out;
slist AdjacentOnes;
//linked list from slist
};
I'm expecting it to stop after outputting 'E' which is the last char in the file. The program never gets into the for loop again after reading the last char. I can't figure out why the while isn't breaking.
Your condition in the while loop is wrong. ios::eof()
isn't
predictive; it will only be set once the stream has attempted
(internally) to read beyond end of file. You have to check after each
input.
The classical way of handling your case would be to define a >>
function for GTable
, along the lines of:
std::istream&
operator>>( std::istream& source, GTable& dest )
{
std::string line;
while ( std::getline( source, line ) && line.empty() ) {
}
if ( source ) {
std::istringstream tmp( line );
std::string name;
int count;
if ( !(tmp >> name >> count) ) {
source.setstate( std::ios::failbit );
} else {
std::vector< char > adjactentOnes;
char ch;
while ( tmp >> ch ) {
adjactentOnes.push_back( ch );
}
if ( !tmp.eof() || adjactentOnes.size() != count ) {
source.setstate( std::ios::failbit );
} else {
dest.Name = name;
dest.Out = count;
for ( int i = 0; i < count; ++ i ) {
dest.AdjacentOnes.addFront( adjactentOnes[ i ] );
}
}
}
}
return source;
}
(This was written rather hastily. In real code, I'd almost certainly factor the inner loop out into a separate function.)
Note that:
We read line by line, in order to verify the format (and to allow resynchronization in case of error).
We set
failbit
in the source stream in case of an input error.We skip empty lines (since your input apparently contains them).
We do not modify the target element until we are sure that the input is correct.
One we have this, it is easy to loop over all of the elements:
int slot = 0;
while ( slot < GTable.size() && fin >> GTable[ slot ] ) {
++ slot;
}
if ( slot != GTable.size )
// ... error ...
EDIT:
I'll point this out explicitly, because the other people responding seem to have missed it: it is absolutely imperative to ensure that you have the place to read into before attempting the read.
EDIT 2:
Given the number of wrong answers this question is receiving, I would like to stress:
Any use of
fin.eof()
before the input is known to fail is wrong.Any use of
fin.good()
, period, is wrong.Any use of one of the values read before having tested that the input has succeeded is wrong. (This doesn't prevent things like
fin >> a >> b
, as long as neithera
orb
are used before the success is tested.)Any attempt to read into
Gtable[slot]
without ensuring thatslot
is in bounds is wrong.
With regards to eof()
and good()
:
The base class of istream
and ostream
defines three
“error” bits: failbit
, badbit
and eofbit
. It's
important to understand when these are set: badbit
is set in case of a
non-recoverable hardward error (practically never, in fact, since most
implementations can't or don't detect such errors); and failbit
is set in
any other case the input fails—either no data available (end of
file), or a format error ("abc"
when inputting an int, etc.).
eofbit
is set anytime the streambuf
returns EOF
, whether this
causes the input to fail or not! Thus, if you read an int
, and the
stream contains "123"
, without trailing white space or newline,
eofbit
will be set (since the stream must read ahead to know where the
int
ends); if the stream contains "123\n"
, eofbit
will not be set.
In both cases, however, the input succeeds, and failbit
will not be
set.
To read these bits, there are the following functions (as code, since I don't know how to get a table otherwise):
eof(): returns eofbit
bad(): returns badbit
fail(): returns failbit || badbit
good(): returns !failbit && !badbit && !eofbit
operator!(): returns fail()
operator void*(): returns fail() ? NULL : this
(typically---all that's guaranteed is that !fail() returns non-null.)
Given this: the first check must always be fail()
or one of the
operator
(which are based on fail
). Once fail()
returns true, we
can use the other functions to determine why:
if ( fin.bad() ) {
// Serious problem, disk read error or such.
} else if ( fin.eof() ) {
// End of file: there was no data there to read.
} else {
// Formatting error: something like "abc" for an int
}
Practically speaking, any other use is an error (and any use of good()
is an error—don't ask me why the function is there).
这篇关于在读取文件时查找文件结尾的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!