5

在尝试从这个答案中读取带有提示的 UTF-16 编码文件时,我遇到的问题是,在读取了几千个字符后,getline-method 开始在垃圾 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文件包含FF,FE字节顺序标记,后跟 100 行,'a'每行 80 s。test.txt这是在 *nix上生成的 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

这是我编译和运行主程序的方式:

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

我所期望的:'a'打印了 8000秒。

实际发生了什么:

打印几千a秒后,输出变为以下垃圾:

aaaaaaaaaa愀愀愀愀愀愀愀愀愀愀

有时看起来像0A00矩形的不可打印字符。

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

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

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

4

1 回答 1

1

一个简单的解决方法(但不是一般的解决方案)

如果您确定输入文件将具有特定的字节顺序,那么您可以简单地硬编码字节顺序,如文档中的示例所示

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

使用硬编码std::little_endian,问题似乎消失了,并且文件被正确读取。它可能不适用于具有相反字节顺序的文件。

于 2019-04-29T18:46:07.530 回答