我写了两个文件,一个是文本模式,另一个是二进制模式,代码如下:
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:
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);
),程序会找到我想要搜索的人。
有人可以解释一下,为什么它在二进制模式下工作,即使我在文本模式下编写文件?
答案 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)
你可以把它想象成一个巨大的霓虹灯,表明真的很疯狂。