我试图读取纯文本文件。在我的情况下,我需要读取每行的行,并处理该信息。我知道C ++有阅读wchars的功能。我尝试了以下方法:
#include <fstream>
#include <iostream>
int main() {
std::wfstream file("file"); // aaaàaaa
std::wstring str;
std::getline(file, str);
std::wcout << str << std::endl; // aaa
}
但正如你所看到的,它并没有读完整行。读取“à”时会停止,这是非ASCII。我该如何解决?
答案 0 :(得分:8)
您需要了解编码的一些基本概念。我建议阅读这篇文章:The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets。基本上你不能假设每个字节都是一个字母,并且每个字母都适合char
。此外,系统必须知道如何从文件中的字节序列中提取字母。
假设您的文件是以UTF-8编码的,这可能是因为您使用的是Linux。我假设您的终端也支持它。如果您使用std::string
直接阅读,使用字符,您将拥有一切正常运作。看:
// olá
#include <iostream>
#include <fstream>
int main() {
std::fstream file("test.cpp");
std::string str;
std::getline(file, str);
std::cout << str << std::endl;
}
输出是你所期望的,但这不是真的正确。看看发生了什么:文件以utf-8编码。这意味着第一行是这个字节序列:
/ / o l á
47 47 32 111 108 195 161
请注意á
is encoded with two bytes。如果你询问字符串的大小(str.size()
),你的确会得到错误的值:7
。发生这种情况是因为字符串认为每个字节都是char。当您将其发送到std::cout
时,该字符串将被提供给终端进行打印。神奇的部分:终端默认使用utf-8。所以它只是假设字符串是utf-8并正确打印6个字符。
你知道它有效,但它确实不对。尝试对数据进行任何字符串操作,您可能会破坏utf-8编码,永远无法再次打印!
让我们去wstring
。它们用wchar_t
存储每个字母,在Linux上有4个字节。这足以容纳任何可能的unicode字符。但它不会直接起作用,因为默认情况下C ++使用"C"
语言环境。区域设置是如何处理系统的各个方面的规范,例如&#34;如何打印日期&#34;或&#34;如何格式化货币价值&#34;甚至&#34;如何解码文本&#34;。最后一个因素很重要,默认的"C"
编码说:&#34;假设一切都是ASCII&#34;。当它正在读取文件并尝试解码非ASCII字节时,它就会无声地失败。
更正很简单:使用UTF-8语言环境。看:
// olá
#include <iostream>
#include <fstream>
#include <locale>
int main() {
std::ios::sync_with_stdio(false);
std::locale loc("en_US.UTF-8"); // You can also use "" for the default system locale
std::wcout.imbue(loc); // Use it for output
std::wfstream file("test.cpp");
file.imbue(loc); // Use it for file input
std::wstring str;
std::getline(file, str); // str.size() will be 6
std::wcout << str << std::endl;
}
您可能会问std::ios::sync_with_stdio(false);
的含义。这是必需的,因为默认情况下C ++流与C流保持同步。这很好,因为您可以在同一个程序中同时使用cout
和printf
。我们必须禁用它,因为C流将破坏utf-8编码并在输出上产生垃圾。