将字符串读写到二进制文件中的调试

4
我正在尝试写入二进制文件,这是我的代码片段:
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

struct user
{
    string ID;
    string password;    
};

int main()
{
    fstream afile;
    afile.open("user.dat",ios::out|ios::binary);

    user person;

    person.ID ="001";

    person.password ="abc";

    afile.write (reinterpret_cast <const char *>(&person), sizeof (person));

    person.ID ="002";

    person.password ="def";

    afile.write (reinterpret_cast <const char *>(&person), sizeof (person));

    afile.close();

    afile.open("user.dat",ios::in|ios::binary);


    while (afile.read (reinterpret_cast <char *>(&person), sizeof (person)))
    {
        cout<<person.ID
            <<" "
            <<person.password
            <<endl;

    }

}

我期望我的控制台输出为:
001 abc
002 def

我得到的是:

相反我得到了

002 def 
002 def

有人能向我解释一下吗?


当你完成一个文件的使用时,像第二次打开afile一样关闭它总是一个好主意。 - Jonny Henly
2
@JonnyHenly,析构函数会关闭它。 - chris
这样行不通。std::string 不是一个普通的数据对象,你不能以这种方式将它们转储到/从文件中读取。请考虑使用 __序列化__。 - Blastfurnace
http://stackoverflow.com/questions/19531797/getting-garbage-values-while-reading-struct-data-from-a-binary-file/19532502#19532502 - Retired Ninja
请注意,std::string 内部有一个指针,您正在写入和读取该指针,而不是字符串本身。 - chris
3个回答

2

std::string是一个类,它的对象并不直接存储字符串的内容。

它的实现方式由具体情况而定,但为了简单起见,您可以这样理解:

std::string有一个成员变量,用于存储指向实际数据的指针(比如ptr)。

   std::string s = "001";

不会将ptr指向“001”字符串的地址;它会分配内存并将该字符串复制到该内存中。然后当您执行以下操作时

    s = "002";

它不需要重新分配内存来存储“002”; 它只是将“002”复制到之前存储“001”的内存中。

这意味着,如果您转储字符串的原始数据,则不会更改。

当您读取字符串的原始数据时,它只会恢复指向“002”的指针

希望这可以帮助您。


请说明如何修复它。 - Mahdi-bagvand

2

很遗憾,你不能这么简单地做到这一点,因此你只能写一个指向std::string的指针而不是字符串包含的内容。你可以按照以下方式将字符串写入二进制文件:

afile.open("user.dat",ios::out|ios::binary);

user person;

person.ID ="001";
person.password ="abc";

int len = person.ID.size();
afile.write(reinterpret_cast<char*>(&len), sizeof(len));
afile.write(const_cast<char*>(person.ID.c_str()), len);

len = person.password.size();
afile.write(reinterpret_cast<char*>(&len), sizeof(len));
afile.write(const_cast<char*>(person.password.c_str()), len);

person.ID ="002";
person.password ="def";

afile.close();

这样你就可以阅读了

afile.open("user.dat",ios::in|ios::binary);

afile.read(reinterpret_cast<char*>(&len), sizeof(len));
person.ID.resize(len);
afile.read(const_cast<char*>(person.ID.c_str()), len);

afile.read(reinterpret_cast<char*>(&len), sizeof(len));
person.password.resize(len);
afile.read(const_cast<char*>(person.password.c_str()), len);

cout << person.ID << " " << person.password << endl;

0

你正在存储一个只包含指针的struct的原始数据。这就是std::string用于存储数据以使字符串可调整大小的方式。你的程序之所以会打印任何数据,仅仅是因为在读取时,对象person仍然存在。如果将程序的读取部分放入单独的程序中,则无法读取任何数据。

要实际使用fstream存储数据,您可以每行存储一个字符串,例如:

afile << person.ID << endl;
afile << person.password << endl;

文件user.dat:
001
abc
002
def

你可以这样阅读它:

afile >> person.ID >> person.password;
while (afile.good())
{
  cout<<person.ID
  <<" "
  <<person.password
  <<endl;
  afile >> person.ID >> person.password;    
}

你还应该查看 包含std::string的类序列化

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接