阅读时意外的EOF

时间:2013-05-20 14:27:13

标签: c++ ifstream

我写了两个文件,一个是文本模式,另一个是二进制模式,代码如下:

write.cpp

struct person {
    char name[20];
    int age;
    float weight;
};

int main(){

    ofstream output("data.txt");
    ofstream output2("data2.txt", ios::out|ios::binary);

    int i;
    person tmp;
    for (i=0; i<4; i++){
        cout<<"Write name: ";
        cin >> tmp.name;
        cout<<endl<<"age: ";
        cin >> tmp.age;
        cout<<endl<<"weight: ";
        cin >> tmp.weight;

        output.write((char*) &tmp, sizeof(tmp));
        output2.write((char*) &tmp, sizeof(tmp));
    }


    output.close();
    output2.close();

    getchar();
    return 0;
}

这2个文件完全相同(我也用十六进制编辑器检查过)。

当我尝试使用以下代码阅读时,我在阅读完第一项后获得了EOF:

read.cpp

int main(){
    bool found = false;
    int pos;
    person tmp;
    ifstream file("data.txt");

    if (!file) {
        cout << "Error";
        return 1;
    }

    while(!file.eof() && !found) {
        file.read( (char*) &tmp, sizeof(tmp));
        cout << "tmp.name: "<<tmp.name<<endl;
        cout << "EOF? "<<file.eof()<<endl;
        if (strcmp(tmp.name, "jack") == 0){
            found = true;
            //pos = file.tellg();
            //pos -= (int) sizeof(tmp);
        }
    }

    file.close();
    cout << endl <<"Press ENTER to continue...";
    getchar();
    return 0;
}

输出

tmp.name: Jacob
EOF? 1
found? 0

但是如果我将ifstream打开成二进制模式(ifstream file("data.txt", ios::in|ios::binary);),程序会找到我想要搜索的人。 有人可以解释一下,为什么它在二进制模式下工作,即使我在文本模式下编写文件?

2 个答案:

答案 0 :(得分:3)

你没有说你的操作系统是什么,所以我只能推测,但是 因为在Unix下文本和二进制模式是相同的,所以它是 可能是Windows。在Windows下,文本模式会执行两项操作 转换:它将单个'\n'转换为两个字符 CRLF行结束,在输入时,它将0x1A视为结尾 文件。根据您的描述,我猜你的数据 不包含0x0A字节(将被视为'\n'), 因为十六进制比较是相同的,但确实如此 包含一个0x1A字节,该字节被解释为文件结尾。

更一般地说,文本文件的正式规则是他们可以的 仅包含可打印字符,'\t''\n''\n'之前没有空格;在 此外,它是实现定义是否最终'\n' 是否需要。总之,你不能写二进制数据 在文本模式下打开的文件,并希望重新读取它。

此外,struct的布局和表示 基本类型是实现定义的,并且可以(和 有时会改变从一个版本到另一个版本。意思是 如果你只是使用ostream::write,你就无法确定 开始能够重新读取未来的数据(而不是其他人 程序可以肯定重读它)。这是有原因的 ostream::write的参数是char const*,而不是void const*; ostream::write它用于写入您拥有的数据 自己格式化(可能是像XDR这样的二进制格式);不要 将内存逐字节转储到文件中。

最后,在read流程中:在file.eof()中使用istream:read 循环条件是一个错误。并使用结果 Person tmp; while ( file.read( ... ) && strcmp( tmp.name, "jack" ) != 0 ) { // ... } 没有首先确保它有效 未定义的行为。你应该是循环 类似的东西:

{{1}}

答案 1 :(得分:1)

1)

  

即使我以文本模式编写文件,有人可以解释为什么它在二进制模式下工作吗?

根据您的说法,当您在十六进制编辑器中查看文件时,文件完全相同,因此在这种情况下,无论您是以二进制模式还是文本模式编写它们都无关紧要。通常,在文本模式下,Windows上会有秘密 - 背后隐藏转换从一个字节到两个字节的换行符。

2)在阅读文件时,你永远不应该使用file.eof()作为while条件 - 这太过于简单了。相反,您应该使用read语句作为条件:

while(file.read( (char*) &tmp, sizeof(tmp)) && !found)

你的程序在有条件的情况下使用它。

3)你的演员:

(char*)

是C演员。你应该使用更加丑陋的C ++演员:

reinterpret_cast<char*>(&tmp)
你可以把它想象成一个巨大的霓虹灯,表明真的很疯狂。