You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用std::wofstream/wifstream二进制序列化数值与宽字符串出错求助

混合数值类型与std::wstring的二进制序列化异常

问题代码

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    wofstream wos("Test.dat", std::ios_base::binary);

    int x1 = 100;
    double d1 = 50.0;
    wstring ostr(L"my string");

    wos.write(reinterpret_cast<wchar_t*>(&x1), sizeof(x1) / sizeof(wchar_t));
    wos.write(reinterpret_cast<wchar_t*>(&d1), sizeof(d1) / sizeof(wchar_t) );
    wos << ostr;

    wos.close();

    int x2 = 0;
    double d2 = .0;
    wstring istr;
    wifstream wis("Test.dat", std::ios_base::binary);

    wis.read(reinterpret_cast<wchar_t*>(&x2), sizeof x2 / sizeof(wchar_t));
    wis.read(reinterpret_cast<wchar_t*>(&d2), sizeof d2 / sizeof(wchar_t));
    wis >> istr;
    wis.close();
    wcout << x2 << "\n" << d2 << "\n" << istr << "\nistr.size() = " << istr.size() << endl;

    return 0;
}

输出对比

预期输出:

100
50
my string
istr.size() = 9

实际输出:

100
0

istr.size() = 0

问题原因

核心问题在于std::wofstream/wifstream是面向宽字符的流,即便指定binary模式,它仍会处理宽字符的编码转换,且所有读写操作以wchar_t为单元:

  • 强制将int、double的二进制内存转成wchar_t*写入时,数值的二进制内容会被当作宽字符序列处理,可能包含流识别为特殊标记的字节(比如null),或因编码转换导致字节偏移,后续读取时无法正确还原数值。
  • 前面的错误写入破坏了流的内部状态和数据对齐,导致后续用<<写入的wstring格式混乱,读取时无法解析。

解决建议

  1. 改用字节流处理二进制序列化:使用std::fstream/ofstream/ifstream,这类流以字节为单位操作,不做编码转换,适合直接读写二进制数值类型。
  2. 手动处理宽字符串的字节转换:将std::wstring转成UTF-8等字节序列后写入字节流,读取时再转回宽字符串,同时要记录字符串长度避免截断。
  3. 使用成熟序列化库:比如Qt的QDataStream、Google Protocol Buffers、Boost.Serialization等,这类库封装了跨平台、编码、数据对齐等细节,避免手动实现的错误。

修正示例代码(使用字节流)

#include <iostream>
#include <fstream>
#include <string>
#include <locale>
#include <codecvt>

using namespace std;

int main()
{
    ofstream os("Test.dat", ios_base::binary);

    int x1 = 100;
    double d1 = 50.0;
    wstring ostr(L"my string");

    // 直接写入数值的二进制字节
    os.write(reinterpret_cast<char*>(&x1), sizeof(x1));
    os.write(reinterpret_cast<char*>(&d1), sizeof(d1));
    
    // 将wstring转为UTF-8字节序列,先写入长度再写内容
    wstring_convert<codecvt_utf8<wchar_t>> converter;
    string utf8_str = converter.to_bytes(ostr);
    size_t str_len = utf8_str.size();
    os.write(reinterpret_cast<char*>(&str_len), sizeof(str_len));
    os.write(utf8_str.c_str(), str_len);

    os.close();

    int x2 = 0;
    double d2 = .0;
    wstring istr;
    ifstream is("Test.dat", ios_base::binary);

    is.read(reinterpret_cast<char*>(&x2), sizeof(x2));
    is.read(reinterpret_cast<char*>(&d2), sizeof(d2));
    
    // 读取字符串长度和UTF-8内容,转回wstring
    size_t str_len = 0;
    is.read(reinterpret_cast<char*>(&str_len), sizeof(str_len));
    string utf8_str_read(str_len, '\0');
    is.read(&utf8_str_read[0], str_len);
    istr = converter.from_bytes(utf8_str_read);

    is.close();
    wcout << x2 << "\n" << d2 << "\n" << istr << "\nistr.size() = " << istr.size() << endl;

    return 0;
}

内容的提问来源于stack exchange,提问作者MDF

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 14:14:51