-2

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

写.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;
}

这两个文件是相同的(我也用十六进制编辑器检查过)。

当我尝试使用以下代码阅读时,阅读第一项后我得到一个 EOF:

读取.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);),程序会找到我想要搜索的人。即使我以文本模式编写文件,有人可以解释我为什么它以二进制模式工作吗?

4

2 回答 2

3

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

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

此外,a 的布局struct和基本类型的表示是实现定义的,并且可能(有时确实)从一个版本更改为另一个版本。这意味着如果您简单地使用ostream::write,则无法确定将来能够重新读取数据(并且没有其他程序可以确保重新读取它)。ostream::write参数ischar const*和 not是有原因的void const*ostream::write它用于写入您自己格式化的数据(可能是像 XDR 这样的二进制格式);不要将内存逐字节转储到文件中。

最后,在这个read过程中:使用file.eof()循环条件是一个错误。并且在 istream:read没有首先确保它有效的情况下使用结果是未定义的行为。你的循环可能应该是这样的:

Person tmp;
while ( file.read( ... ) && strcmp( tmp.name, "jack" ) != 0 ) {
    //  ...
}
于 2013-05-20T16:02:37.720 回答
2

1)

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

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

2) 你不应该在读取文件时使用 file.eof() 作为 while 条件——这太挑剔了。相反,您应该使用 read 语句作为条件:

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

您的程序可以在有条件的情况下使用。

3)你的演员:

(char*)

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

reinterpret_cast<char*>(&tmp)

你可以把它想象成一个巨大的霓虹灯标志,表明正在发生一些非常疯狂的事情。

于 2013-05-20T14:53:44.717 回答