编辑:
所以问题似乎在于Windows将某些特殊字节序列视为文本模式下的文件结尾。使用二进制模式读取文件可以解决此问题,std::ifstream fin("filename", std::ios::binary);
,然后像你已经做的那样将数据复制到wstring中。
最简单的非便携式解决方案是将文件数据直接复制到wchar_t数组中。这取决于Windows上的wchar_t是2个字节,并使用UTF-16作为其编码。
以完全方便携式的方式将UTF-16转换为区域设置特定的wchar_t编码可能会有些困难。
以下是标准C++库中可用的Unicode转换功能(虽然VS 10和11仅实现了3,4和5项)
codecvt<char32_t,char,mbstate_t>
codecvt<char16_t,char,mbstate_t>
- codecvt_utf8
- codecvt_utf16
- codecvt_utf8_utf16
- c32rtomb/mbrtoc32
- c16rtomb/mbrtoc16
以及每个功能所做的事情
- 一个始终在UTF-8和UTF-32之间转换的codecvt facet
- 在UTF-8和UTF-16之间进行转换
- 在UTF-8和UCS-2或UCS-4之间进行转换,具体取决于目标元素的大小(BMP外的字符可能会被截断)
- 使用UTF-16编码方案的一系列char之间进行转换,并且用UCS-2或UCS-4表示
- 在UTF-8和UTF-16之间进行转换
- 如果定义了宏
__STDC_UTF_32__
,则这些函数将在当前区域设置的char编码和UTF-32之间进行转换
- 如果定义了宏
__STDC_UTF_16__
,则这些函数将在当前区域设置的char编码和UTF-16之间进行转换
如果定义了__STDC_ISO_10646__
,则直接使用codecvt_utf16<wchar_t>
进行转换应该没问题,因为该宏指示在所有语言环境中,wchar_t值对应于Unicode charters的短名称(因此意味着wchar_t足够大来容纳任何这样的值)。
不幸的是,没有定义从UTF-16直接到wchar_t的内容。可以按UTF-16 -> UCS-4 -> mb(如果__STDC_UTF_32__
) -> wc的顺序进行转换,但将丢失任何无法在区域设置的多字节编码中表示的内容。当然,无论如何,从UTF-16到wchar_t的转换都会丢失任何在区域设置的wchar_t编码中无法表示的内容。
因此,将它制作成可移植的可能并不值得,您可以将数据读入wchar_t数组中,或使用一些其他Windows特定设施,例如文件上的_O_U16TEXT模式。
这样做可以在任何地方构建和运行,但实际工作时需要进行一堆假设:
#include <fstream>
#include <sstream>
#include <iostream>
int main ()
{
std::stringstream ss;
std::ifstream fin("filename");
ss << fin.rdbuf();
std::string const &s = ss.str();
if (s.size()%sizeof(wchar_t) != 0)
{
std::cerr << "file not the right size\n";
return 1;
}
std::wstring ws;
ws.resize(s.size()/sizeof(wchar_t));
std::memcpy(&ws[0],s.c_str(),s.size());
}
你可能至少需要添加处理字节序和'BOM'的代码。同时,Windows的换行符不会自动转换,因此需要手动操作。
wchar_t*
以初始化wstring
。我唯一要检查的是文件是否以二进制模式打开,但我不认为在那里犯错误会显示你的症状。 - Mark Ransom