C++ - 正确地将std::string写入二进制文件

3
我正在尝试从cin获取字符串,然后将其写入二进制文件。我读到纯字符串无法正常工作,所以尝试将其转换为char*。

以下代码可以正常写入(...可能),但只有前8个字符,因此文件输出是不完整的。

std::string nick, ip, port;

std::cout << "IP: ";
std::cin >> ip;
std::cout << "port: ";
std::cin >> port;

ofstream file1("lastServers.bin", ios::out | ios::binary);
if (file1.good())
{
    const char* p_IP = ip.c_str();
    const char* p_PORT = port.c_str();
    int length = sizeof(&p_IP)+sizeof(&p_PORT);
    char* tmp1 = new char[length];

    int index = 0;
    memcpy((tmp1 + index), p_IP, sizeof(&p_IP));
    index = index + sizeof(&p_IP);
    memcpy((tmp1 + index), p_PORT, sizeof(&p_PORT));

    file1.write(tmp1, length);

    file1.close();
    delete[] tmp1;
}

else
{
    std::cout << "file error write" << endl;
}

感谢您提前的任何帮助 :)



该段落无需翻译。

1
“我读过纯字符串编写不起作用”的说法,你能澄清一下吗?你在哪里看到这个信息的?” - BoBTFish
我的意思是,像(string, sizeof(string))这样写是不正确的,因为我认为。 - Skipper
3
我不明白。你想要做什么,而file << ip << port << nick;不能完成吗?因为这似乎是你在这里尝试构建的内容。 - Wintermute
sizeof(&p_IP)sizeof(&p_PORT) 是指针的大小,可能是8。 - molbdnilo
3
我需要指出的是file1.good()的结果在这里没有很好地定义。您需要使用file1.is_open()! file1.fail(),或者只使用file1 - James Kanze
2个回答

6

您的代码可以写成:

ofstream file1("lastServers.bin", ios::out | ios::binary);
if (file1.good()) {
    file1.write(ip.c_str(), ip.size());
    file1.write(port.c_str(), port.size());
    file1.close();
}
else {
    std::cout << "file error write" << endl;
}

string::c_str()函数返回字符串中文本的const指针。 string::size()函数返回字符串中字符的数量。

在写入文件之前,您不需要将数据连接起来,先写一个再写另一个会得到相同的结果。

如果您想编写C类型的代码而不是C ++,则可以使用strlen(p_IP)来获取IP字符串的长度,而不是使用sizeof。

sizeof运算符给出类实例的大小,即对象的大小,但是string对象的大小永远不会受到其管理的字符串的大小的影响。

在C ++中,管理某些内容的对象(考虑管理字符的字符串,容器管理其内容等)通常具有确定其管理内容大小的方法。对于std :: string和其他STL容器,该方法是size()。

请注意,以这种格式编写这些字符串意味着您无法确定一个字符串何时结束,另一个字符串何时开始。要考虑的两个选项是使用您知道不会出现在任何字符串中的终止字符,或者在文本字符串本身之前将字符串的长度写入文件。我不会在此进行详细说明,因为原始问题中没有提出。


@giorgim 这是一个很好的问题,我已经添加了一个额外的段落来提出这个问题。 - Steve Kidd
如果您想使用空终止符,可以编写file1.write(ip.c_str(), ip.size() + 1),因为c_str()返回指向以空字符结尾的字符串的指针。 - Steve Kidd
我认为你的意思是,如果你尝试将它作为字符串读取,那么你就看不到第二个字符串。我同意。我认为你需要将文件视为二进制并解析它 - 例如,将其读入内存缓冲区,在缓冲区中搜索第一个空终止符号 - 将这些字符分配给第一个字符串。在缓冲区中搜索第二个空终止符号 - 将这些字符分配给第二个字符串,以此类推。 - Steve Kidd
它仍将工作。如果字符串包含空终止符,那么整个字符串都会被写入文件。"abc"+ nullterm + "de" 表示 size() 返回 6。但是,如果您的字符串可能包含空终止符,这意味着您不能将其用作字符串终止符 - 这就是您需要选择不同终止符的时候(只有当您知道没有字符串将包含该字符时),或使用我提到的另一个选项,即将字符串的长度写入文件(最可能为二进制的固定4字节或8字节),然后是字符串中的字符。 - Steve Kidd

2

sizeof 返回的是字符串对象在内存中的大小,而不是字符串本身的长度。具体来说,sizeof(&p_IP) 返回的是指向 p_IP 的指针的大小,在 32 位系统上始终为 4 字节。你的变量 length 并没有计算出正确的值。要获取 char* 的长度,请使用 strlen


2
虽然从技术上讲是正确的,但这个答案并没有提供解决这个问题的“正确”方法。即使假设您确实想要从std::string获取char*+长度,使用myString.size()(或length())比使用strlen更好。 - BoBTFish
我以为问题是为什么他只保存了8个字节的数据。最后,当然不需要使用char* - Anton Poznyakovskiy

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