使用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格式混乱,读取时无法解析。
解决建议
- 改用字节流处理二进制序列化:使用
std::fstream/ofstream/ifstream,这类流以字节为单位操作,不做编码转换,适合直接读写二进制数值类型。 - 手动处理宽字符串的字节转换:将
std::wstring转成UTF-8等字节序列后写入字节流,读取时再转回宽字符串,同时要记录字符串长度避免截断。 - 使用成熟序列化库:比如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
相关产品推荐
相关产品推荐

