std :: getline和UTF16(LE)文件流 - 无法正常工作

时间:2014-08-17 11:48:08

标签: c++11 unicode

以下应该有效 - 我找不到它不应该的原因:

    std::fstream f;
    std::string myoutput;
    f.imbue(std::locale(f.getloc(), new std::codecvt_utf16<wchar_t, std::little_endian | std::consume_header>));
    f.open("c:\\test.txt", std::ios::in);
    std::getline(f, myoutput);

代码在以下文件上执行(十六进制 - 它应拼写为“hello world”):

  

FF FE 68 00 65 00 6C 00 6C 00 6F 00 20 00 77 00 6F 00 72 00 6C 00 64   00

最终目标是抽象编码,始终考虑文件UTF-8,除非第一个字节是BOM。现在,上面的代码将在读取BOM后执行并注意到它是UTF-16。因此它应该读取UTF-16文件,并将其转换为utf-8字符串。

然而,std :: getline不会忽略BOM(容易修复),但是它并不尊重UTF-16使用2个字节的事实。 (并在看到“0”后读取前3个字节后停止。)

现在我当然可以使用std :: wfstream。但是,由于我希望从用户“隐藏”unicode类型,所有“文件流”都存储在容器中以供引用。因此,所有这些文件流的签名必须相同 - 并且基于charstd::string

1 个答案:

答案 0 :(得分:2)

如果您将文件打开为basic_fstream<char>,则您已将外部和内部字符宽度设置为1个字节,并且您正在应用的区域设置构面将永远不会被使用。

读入字符串并应用wstring_convert两次,或应用wbuffer_convert使内部字符宽度更大,然后是wstring_convert:

std::fstream f;
f.open("test.txt", std::ios::in | std::ios::binary);

std::wbuffer_convert<std::codecvt_utf16<wchar_t,
                           0x10ffff, // note your 2nd parameter was wrong
                           std::little_endian // or consume_header, not both
                     >> cvt1(f.rdbuf());
std::wistream wide_f(&cvt1);
std::wstring wstr;
std::getline(wide_f, wstr);

std::wstring_convert<std::codecvt_utf8<wchar_t>> cvt2;
std::string u8str = cvt2.to_bytes(wstr);

std::cout << u8str << '\n';