为什么“ wifstream”上的“ getline”会从UTF-16编码文件中读取乱码输入?

时间:2019-04-29 17:48:42

标签: c++ linux utf-16 wifstream

在尝试从this answer读取带有提示的UTF-16编码文件时,我遇到的问题是,在读取几千个字符后,getline方法开始在垃圾mojibake中读取。 / p>

这是我的主要爱好:

#include <cstdio>
#include <fstream>
#include <iostream>
#include <codecvt>
#include <locale>

int main(void) {

    std::wifstream wif("test.txt", std::ios::binary);
    setlocale(LC_ALL, "en_US.utf8");
    if (wif.is_open())
    {
        wif.imbue(
            std::locale(
                wif.getloc(),
                new std::codecvt_utf16<wchar_t, 0x10ffff, std::consume_header>
            )
        );

        std::wstring wline;
        while (std::getline(wif, wline))
        {
            std::wcout << wline;
        }

        wif.close();
    } 

    return 0;
}

test.txt文件包含FFFE字节顺序标记,后跟100行,每行80个'a'。这是一个在* nix上生成test.txt的bash脚本:

#!/bin/bash

echo -n -e \\xFF\\xFE > test.txt
for i in $(seq 1 100)
do
  for i in $(seq 1 80)
  do
    echo -n -e \\x61\\x00 >> test.txt
  done
  echo -n -e \\x0A\\x00 >> test.txt
done

这是我编译和运行main的方式:

g++-8 -std=c++17 -g main.cpp -o m && ./m

我的期望:打印了8000 'a'

实际发生的情况:

在打印了几千个a之后,输出变为以下垃圾:

  

aaaaaaaaaa愀愀愀愀愀愀愀愀愀愀

,偶尔还有不可打印的字符,它们看起来像0A00的矩形。

字符的二进制代码点值为110000100000000,因此看起来像a字节,后跟0字节。

似乎在读取期间丢失了一些字节,从那时起,所有内容都未对齐,并且所有其余符号均被错误地解码。或者,因为输出以0A00-thingie结尾,所以可能是在读取数千个a之后,字节序反转了,但是这种行为也毫无意义。

为什么会发生这种情况,最简单的解决方法是什么?

1 个答案:

答案 0 :(得分:1)

一种简单的解决方法(但不是通用解决方案)

如果您确定输入文件具有特定的字节序,则可以简单地对字节序as shown in the example in the documentation进行硬编码:

        wif.imbue(
            std::locale(
                wif.getloc(),
                new std::codecvt_utf16<wchar_t, 0x10ffff, std::little_endian>
            )
        );

使用硬编码的std::little_endian,问题似乎消失了,并且可以正确读取文件。字节序相反的文件可能无法使用。