在读取文件时查找文件结尾 [英] Finding end of file while reading from it

查看:205
本文介绍了在读取文件时查找文件结尾的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  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; i dest.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>>
    b
    ,只要 a 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 neither a or b are used before the success is tested.)

  • Any attempt to read into Gtable[slot] without ensuring that slot 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆