奇怪的ifstream行为

时间:2016-03-16 12:51:18

标签: c++ algorithm

编写代码将对象写入文件,读取并在屏幕上打印

#include<iostream>
#include<fstream>
#include<cstring>
using namespace std;
////////////////////////////////////////////////////////////
class employee{
    private:
        string name;
        unsigned long ID;
    public:
        employee():name(""),ID(0){}
        void putdata(){cout<<"Enter employee's name: ";cin>>name;cout<<"Enter employee's ID: ";cin>>ID;}
        void getdata(){cout<<"Employee's name is: "<<name<<endl;cout<<"Employee's ID is: "<<ID<<endl;}
        friend ostream& operator << (ostream&,employee&);
        friend istream& operator >> (istream&,employee&);
};

ostream& operator << (ostream& f,employee& emp){ // запись объекта в файл
    f<<emp.ID<<"-"<<emp.name<<"?";
    return f;
}

istream& operator >> (istream& f,employee& empl){ // чтение объекта из файла
    char dummy;
    f>>empl.ID>>dummy;
    f>>dummy;
    empl.name="";
    while(dummy!='?'){
        empl.name+=dummy;
        f>>dummy;       
    }
}
////////////////////////////////////////////////////////////
int main(){
    char ch='y';
    ofstream file1;
    ifstream file2;
    file1.open("TAB.txt");
    employee one;
    while(ch=='y'){ // цикл для записи
        one.putdata();
        file1<<one; // write data into file
        cout<<"Go on?(y,n): ";cin>>ch;
    }
    file1.close();
    file2.open("TAB.txt");
    while(file2.good()){ // цикл для чтения из файла
        file2>>one;
        one.getdata();      
    }
    file2.close();
    system("pause");
    return 0;
}

输入对象后,程序将它们打印出来并挂起。我想while(file2.good())有问题,但我不确定。有谁评论?

2 个答案:

答案 0 :(得分:1)

您错过的是,在您阅读过去文件末尾之前,EOF未设置。最后一次成功读取将读取(但不是过去)文件结尾,因此EOFfalsegood()true,但不会再有数据在流上(所以下一次读取将失败)。

这就是您需要检查流中的读取是否成功的原因。为了在布尔上下文中使用流对象时(在/ if测试时),它将自身转换为boolean,该值是流的状态。

 if (stream) {
      std::cout << "stream is in good state\n";
 }

输入operator>>也返回一个流(因此可以链接),因此读取的结果也可以用于测试。

 if (stream >> value) {
      std::cout << "The read worked.\n";
 }

您的问题是您在阅读后没有正确检查输入流的状态。

istream& operator >> (istream& f,employee& empl)
{
    char dummy;
    f>>empl.ID>>dummy;  // Did this work?
                        // You did not test the state of `f` after the read.
    f>>dummy;
    empl.name="";
    while(dummy!='?'){
        empl.name+=dummy;
        f>>dummy;          // Again if this read fails
                           // because you reached the end of file
                           // then the variable 'dummy' is not updated
                           // then this will go into an infinite loop.
    }
}

每次阅读都应该检查流的状态。

std::istream& operator>>(std::istream& f, employee& empl)
{
    // The other standard thing is that if the read fails.
    // then you should not alter the state of your object.
    // so read into a temporary object.
    char dummy;


    employee tmp;
    if (f >> tmp.id >> dummy && dummy == '-')
    {
        // We have correctly read the ID (and following '-' char)
        // Note: The output operator outputs '-' after the ID.
        // Now we try and read the name.

        // While the read of the character worked.
        // and the character is not '?' keep adding it to
        // name. If we reach then end of the file this
        // loop will exit.
        while(f >> dummy && dummy != '?')
        {
           tmp.name += dummy;
        }

        // If the stream is still good.
        // then update the object.
        // If the stream is not good then something went wrong
        // we reached the end of file before we found the '?'
        if (f)
        {
            using std::swap;
            swap(tmp, empl);
        }
    }
    return f;
}

现在输入操作符很好。我们可以正确地编写输出循环。

while(file2.good()){
    file2>>one;
    one.getdata();      
}

问题是file2>>one可能会失败。你应该测试一下。

while(file2.good()){
    if (file2 >> one) {
        one.getdata();     
    } 
}

但要正确地将读取作为时间的条件。如果读取失败,你甚至不进入循环。

while(file2 >> one)
{
    one.getdata();      
}

答案 1 :(得分:0)

它最终起作用(我不能相信):

#include<iostream>
#include<fstream>
#include<cstring>
using namespace std;
////////////////////////////////////////////////////////////
class employee{
    private:
        string name;
        unsigned long ID;
    public:
        employee():name(""),ID(0){}
        void putdata(){cout<<"Enter employee's name: ";cin>>name;cout<<"Enter employee's ID: ";cin>>ID;}
        void getdata(){cout<<"Employee's name is: "<<name<<endl;cout<<"Employee's ID is: "<<ID<<endl;}
        friend ostream& operator << (ostream&,employee&);
        friend istream& operator >> (istream&,employee&);
};

ostream& operator << (ostream& f,employee& emp){ // запись объекта в файл
    f<<emp.ID<<"-"<<emp.name<<"?";
    return f;
}

istream& operator >> (istream& f,employee& empl){ // чтение объекта из файла
    char dummy;
    f>>empl.ID>>dummy;
    f>>dummy;
    empl.name="";
    while(dummy!='?'){
        empl.name+=dummy;
        f>>dummy;       
    }
}
////////////////////////////////////////////////////////////
int main(){
    char ch='y';
    ofstream file1;
    ifstream file2;
    file1.open("TAB.txt");
    employee one;
    while(ch=='y'){ // цикл для записи
        one.putdata();
        file1<<one; // write data into file
        cout<<"Go on?(y,n): ";cin>>ch;
    }
    file1.close();
    file2.open("TAB.txt");
    while(file2.good()&&file2.peek()!=EOF){ // цикл для чтения из файла

        file2>>one;
        one.getdata();      
    }
    file2.close();
    system("pause");
    return 0;
}

我已添加file2.peek()!=EOF条件