在尝试使用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
文件包含FF
,FE
字节顺序标记,后面跟着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。
实际发生了什么:
打印几千个a
s后,输出变为以下垃圾:
aaaaaaaaaa愀愀愀愀愀愀愀愀愀愀
偶尔也是不可打印的字符,在矩形中看起来像0A00
。
愀
-character的二进制代码点值为110000100000000
,因此它看起来像a
-byte后跟0
-byte。
看起来似乎在读取期间丢失了一些字节,从那时起,一切都未对齐,并且所有剩余的符号都被错误地解码。或者,因为输出以0A00
-thingie结尾,可能是在阅读了几千个a
s之后字节顺序被反转,但这种行为也没有任何意义。
为什么会发生这种情况,最简单的解决办法是什么?
一个简单的解决方法(但不是一般解决方案)
如果您确定输入文件将具有特定的字节序,那么您只需硬编码字节序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
,问题似乎消失了,文件被正确读取。它可能不适用于具有相反字节顺序的文件。