关于此问题,有很多问题,但大多数人都没有提到将wstring写回文件。 例如,我发现这是为了阅读:
// open as a byte stream
std::wifstream fin("/testutf16.txt", std::ios::binary);
// apply BOM-sensitive UTF-16 facet
fin.imbue(std::locale(fin.getloc(),
new std::codecvt_utf16<wchar_t, 0x10ffff, std::consume_header>));
// read
std::wstring ws;
for(wchar_t c; fin.get(c); )
{
std::cout << std::showbase << std::hex << c << '\n';
ws.push_back(c);
}
我尝试过类似的东西写作:
std::wofstream wofs("/utf16dump.txt", std::ios::binary);
wofs.imbue(std::locale(wofs.getloc(),
new std::codecvt_utf16<wchar_t, 0x10ffff, std::consume_header>));
wofs << ws;
但它产生垃圾,(或Notpad ++和vim无法解释它)。 如标题Im on Win,原生C ++,VS 2010中所述。
输入文件:
t€stUTF16✡
test
这就是结果:
t€stUTF16✡
test
转换为十六进制:
0000000: 7400 ac20 7300 7400 5500 5400 4600 3100 t.. s.t.U.T.F.1.
0000010: 3600 2127 0d00 0a00 7400 6500 7300 7400 6.!'....t.e.s.t.
0000020: 0a
...
vim正常输出:
t ^ @¬s^ @ t ^ @ U ^ @ T ^ @ F ^ @ 1 ^ @ 6 ^ @!'^ M ^ @ ^ @ T ^ | E ^ @小号^ @ T ^ @
编辑: 我最终使用UTF8。 Andrei Alexandrescu说这是最好的编码所以没有大的损失。 :)
答案 0 :(得分:3)
您的类似代码 - 不是。尽管the documentation说
,但您删除了std::ios::binary
样式
应将字节流写入二进制文件;如果写入文本文件,它可能会被破坏。
NL-&gt; ASCII模式下的CRLF转换不会对UTF-16文件做很多事情,因为它会插入一个字节0x0D而不是两个字节0x00 0x0D。
答案 1 :(得分:2)
如果您使用C++11
标准,那就很容易了(因为还有很多额外的包含,例如"utf8"
可以永远解决这个问题)。
但是如果你想使用旧标准的多平台代码,你可以使用这种方法来编写流:
stxutif.h
以ANSI模式打开文件,并将BOM添加到文件的开头,如下所示:
std::ofstream fs;
fs.open(filepath, std::ios::out|std::ios::binary);
unsigned char smarker[3];
smarker[0] = 0xEF;
smarker[1] = 0xBB;
smarker[2] = 0xBF;
fs << smarker;
fs.close();
然后将文件打开为UTF
并在那里写下您的内容:
std::wofstream fs;
fs.open(filepath, std::ios::out|std::ios::app);
std::locale utf8_locale(std::locale(), new utf8cvt<false>);
fs.imbue(utf8_locale);
fs << .. // Write anything you want...
答案 2 :(得分:1)
对于输出,您希望使用generate_header
代替consume_header
。