尽管付出了很多努力,但这是一个我无法解决的问题。所以我完全陷入困境,请帮忙!
对于常规的“ASCII”模式,以下简化文件和流输出
FILE *fa = fopen("utfOutFA.txt", "w");
fprintf(fa, "Line1\nLine2");
fclose(fa);
ofstream sa("utfOutSA.txt");
sa << "Line1\nLine2";
sa.close();
结果,当然,完全相同的文本文件(十六进制转储):
00000000h: 4C 69 6E 65 31 0D 0A 4C 69 6E 65 32 ; Line1..Line2
新行\n
扩展为CRLF:0D 0A
- 适用于Windows。
现在,我们对Unicode输出执行相同的操作,即UTF-16 LE,这是一种“默认”。文件输出
FILE *fu = fopen("utfOutFU.txt", "w, ccs=UNICODE");
fwprintf(fu, L"Line1\nLine2");
fclose(fu);
导致此内容:
00000000h: FF FE 4C 00 69 00 6E 00 65 00 31 00 0D 00 0A 00 ; ÿþL.i.n.e.1.....
00000010h: 4C 00 69 00 6E 00 65 00 32 00 ; L.i.n.e.2.
考虑到BOM和字节序,看起来非常正确,包括CRLF:0D 00 0A 00
。但是,类似的流输出
wofstream su("utfOutSU.txt");
su.imbue(locale(locale::empty(), new codecvt_utf16<wchar_t, 0x10ffffUL,
codecvt_mode(generate_header + little_endian)>));
su << L"Line1\nLine2";
su.close();
导致一个字节减少,整体文本文件错误:
00000000h: FF FE 4C 00 69 00 6E 00 65 00 31 00 0D 0A 00 4C ; ÿþL.i.n.e.1....L
00000010h: 00 69 00 6E 00 65 00 32 00 ; .i.n.e.2.
原因是CRLF的扩展错误:0D 0A 00
。这是一个错误吗?或者我做错了什么?
我使用Microsoft Visual Studio编译器(14.0和其他)。我尝试使用流endl
而不是\n
- 结果相同!我试图先放su.imbue()
,然后放su.open()
- 都一样!我还检查了UTF-8输出(文件ccs=UTF-8
和流codecvt_utf8
- 没问题,因为CRLF与ASCII模式保持一致:0D 0A
我感谢您对此问题的任何想法和意见。
答案 0 :(得分:3)
当您imbue()
std::wofstream
新的区域设置时,您正在消除其原始区域设置。不要使用locale::empty()
,而是使用su.getloc()
,因此新的语言环境会在修改之前复制旧语言环境。
另外,在旁注中,codecvt_utf16
的最后一个模板参数是位掩码,因此codecvt_mode(generate_header + little_endian)
确实应该是std::generate_header | std::little_endian
。
su.imbue(std::locale(su.getloc(), new codecvt_utf16<wchar_t, 0x10ffffUL,
std::generate_header | std::little_endian>));
答案 1 :(得分:0)
我发现此问题源于您以文本模式写入文件的事实。您想要做的是用二进制打开输出文件,问题将得到解决,就像这样:
wofstream su("utfOutSU.txt", ofstream::out | ofstream::binary);
su.imbue(locale(su.getloc(), new codecvt_utf16<wchar_t, 0x10ffffUL,
codecvt_mode(generate_header + little_endian)>));
su << L"Line1\r\nLine2";
su.close();
在编写文本时,某些“聪明”可能是在幕后完成的。