跨平台(Windows和Mac)Boost C++序列化std::wstring

6
我正在使用Boost C++库在一个程序中实现序列化,该程序是为Windows(使用Visual Studio 2008)和Mac(使用GCC)构建的。该程序在大约30个类中使用宽字符串(std::wstring)。根据不同平台,在保存到文件时(通过boost::archive::text_woarchive),输出文件中的宽字符串表示方式也有所不同。
Windows下保存:
H*e*l*l*o* *W*o*r*l*d*!* ...

保存在MacOSX下:

H***e***l***l***o*** ***W***o***r***l***d***!*** ...

其中 * 是空字符。

当我尝试使用 Mac 构建(反之亦然)读取在 Windows 下创建的文件时,我的程序会崩溃。

据我目前的了解,Windows 本地使用每个宽字符 2 个字节,而 MacOSX(以及我想 Unix 一般)使用 4 个字节。

我已经找到了可能的解决方案,例如 utf8_codecvt_facet.cppUTF8-CPPICUDinkumware,但是我还没有看到一个例子可以与我已有的内容配合使用(例如,此时我更愿意不重写五个月的序列化工作):

std::wofstream ofs( "myOutputFile" );
boost::archive::text_woarchive oa( ... );
//... what do I put here? ...
oa << myMainClass;

myMainClass 包含宽字符串和指向其他类的 Boost 智能指针,这些类反过来又被序列化。


有没有办法为wstring添加自己的load和save函数的专业化? - bames53
你是什么意思?将序列化拆分为单独的“load”和“save”函数?我知道如何做到这一点,但如果我要编写这些功能,我不确定应该在wstrings上执行哪种类型的转换。 - Tymek
我会采用bames53的想法,为wstring编写boost::serialization例程的专门版本。这样,您可以选择每个字符2个或4个字节,并在两个平台上坚持使用它。 - fileoffset
@Tymek 不,我提到的加载和保存函数只是附带的。我只是想说你可以用自己的代码覆盖默认的序列化函数,例如将wstring转换为UTF-8字符串进行序列化。例如,如果通过模板实现了wstring序列化,你可以为wstring创建自己的模板特化。 - bames53
你需要决定一个交换格式(UTF-8,UTF-16,UTF-16BE,UTF16-LE,UTF32...)。 - curiousguy
@curiousguy 这是UTF-8编码。我仍在努力弄清楚如何以UTF-8格式存储数据。有没有使用Boost序列化的示例? - Tymek
2个回答

2

wofstreamtypedef basic_ofstream<wchar_t, char_traits<wchar_t> > wofstream;

在Linux上,你需要声明一个自定义的ofstream来处理16位字符(在Linux上)。 可以按照以下方式完成:

typedef std::uint16_t Char16_t;
typedef basic_ofstream<Char16_t, char_traits<Char16_t> > wofstream_16;

现在wofstream_16 可以在不同平台上无缝使用,处理16位宽字符。

谢谢 Vine'th。我尝试添加这个,但是我遇到了编译问题:error: no matching function for call to boost::archive::text_woarchive::text_woarchive(SaveSession()::wofstream_16&) ... candidates are: boost::archive::text_woarchive::text_woarchive(std::wostream&, unsigned int) ... boost::archive::text_woarchive::text_woarchive(const boost::archive::text_woarchive&) 有什么想法吗? - Tymek
我认为你需要在myMainClass中添加一个重载的<<运算符,它接受wofstream_16&(猜测,没有源代码很难确定问题所在)。希望对你有帮助。 - vine'th

0

对于这个问题,我有一个简单的解决方案。只需要理解官方文档中的这些语句并将它们转换为C++语法即可:

  1. 打开一个宽字符流。
  2. 更改流区域设置以使用boost::archive::codecvt_null。
  3. 使用no_codecvt标志创建存档。

所以所有东西放在一起看起来像这样(输出到文件):

#include <fstream>
#include <locale>

#include <boost/archive/codecvt_null.hpp>
#include <boost/archive/text_woarchive.hpp>
#include <boost/archive/text_wiarchive.hpp>

// (1)
std::wofstream ofs( "myOutputFile.dat" );

// (2)
std::locale loc( ofs.getloc(), new boost::archive::codecvt_null<std::ostream::char_type>() );
ofs.imbue( loc );

// (3) (note text_woarchive)
boost::archive::text_woarchive oa( ofs, boost::archive::no_codecvt );

oa << myMainClass;

对于文件输入,同样的思路也适用:

std::wifstream ifs( "myInputFile.dat" );

std::locale loc( ifs.getloc(), new boost::archive::codecvt_null<std::ostream::char_type>() );
ifs.imbue( loc );

boost::archive::text_wiarchive ia( ifs, boost::archive::no_codecvt );

ar >> myMainClass;

现在两个平台上的输出文件都是相同的,并且以UTF8格式存储。


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