UTF-16流中的错误CRLF?

时间:2017-09-19 19:54:04

标签: c++ visual-c++ unicode newline

尽管付出了很多努力,但这是一个我无法解决的问题。所以我完全陷入困境,请帮忙!

对于常规的“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

我感谢您对此问题的任何想法和意见。

2 个答案:

答案 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();

在编写文本时,某些“聪明”可能是在幕后完成的。