为什么`wifstream`上的`getline`读取来自UTF-16编码文件的乱码输入?

问题描述 投票:4回答:1

在尝试使用this answer的提示读取UTF-16编码文件时,我遇到的问题是,在阅读了几千个字符之后,getline方法开始读取垃圾mojibake。

这是我的主要内容:

#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's。这是一个在* 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's。

实际发生了什么:

打印几千个as后,输出变为以下垃圾:

aaaaaaaaaa愀愀愀愀愀愀愀愀愀愀

偶尔也是不可打印的字符,在矩形中看起来像0A00

-character的二进制代码点值为110000100000000,因此它看起来像a-byte后跟0-byte。

看起来似乎在读取期间丢失了一些字节,从那时起,一切都未对齐,并且所有剩余的符号都被错误地解码。或者,因为输出以0A00-thingie结尾,可能是在阅读了几千个as之后字节顺序被反转,但这种行为也没有任何意义。

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

c++ linux utf-16 wifstream
1个回答
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,问题似乎消失了,文件被正确读取。它可能不适用于具有相反字节顺序的文件。

© www.soinside.com 2019 - 2024. All rights reserved.