当我使用 wifstream 将文本文件读取到宽字符串 (std::wstring) 时,流实现是否支持不同的编码 - 即它可以用于读取例如ASCII、UTF-8 和 UTF-16 文件?
如果没有,我该怎么办?
(如果有影响,我需要阅读整个文件)
最佳答案
C++ 通过 std::locale
和 facet std::codecvt
支持字符编码。一般的想法是 locale
对象描述了系统的各个方面,这些方面可能因文化而异,(人类)语言因语言而异。这些方面被分解为 facet
,它们是定义本地化相关对象(包括 I/O 流)如何构造的模板参数。当您从 istream
读取或写入 ostream
时,每个字符的实际写入都会通过语言环境的方面进行过滤。这些方面不仅涵盖 Unicode 类型的编码,还涵盖各种不同的功能,例如如何写入大数字(例如使用逗号或句点)、货币、时间、大小写以及许多其他细节。
然而,仅仅因为存在进行编码的工具并不意味着标准库实际上可以处理所有编码,也不意味着这些代码可以简单地正确执行。即使是你应该读入的字符大小(更不用说编码部分)这样基本的东西也很困难,因为 wchar_t
可能太小(破坏你的数据)或太大(浪费空间) ,而最常见的编译器(例如 Visual C++ 和 Gnu C++)确实在其实现的大小上有所不同。所以一般需要找外部库来做实际的编码。
- iconv一般认为是正确的,但很难找到如何将其绑定(bind)到 C++ 机制的示例。
- jla3ep mentions libICU ,这非常彻底,但 C++ API没有尝试与标准很好地配合(据我所知:您可以扫描 examples 看看是否可以做得更好。)
我能找到的涵盖所有基础的最直接示例来自 Boost 的 UTF-8 codecvt facet ,其中一个示例专门尝试对 UTF-8 (UCS4) 进行编码以供 IO 流使用。它看起来像这样,尽管我不建议逐字复制它。在 the source 中需要更多的挖掘理解它(我并不声称):
typedef wchar_t ucs4_t;
std::locale old_locale;
std::locale utf8_locale(old_locale,new utf8_codecvt_facet<ucs4_t>);
...
std::wifstream input_file("data.utf8");
input_file.imbue(utf8_locale);
ucs4_t item = 0;
while (ifs >> item) { ... }
要了解有关区域设置的更多信息,以及它们如何使用构面(包括 codecvt
),请查看以下内容:
- Nathan Myers 有一个 thorough explanation of locales and facets . Myers 是语言环境概念的设计者之一。他有more formal documentation如果你想涉水而过。
- Apache 的标准库实现(以前称为 RogueWave 的)具有 full list of facets .
- Nicolai Josuttis 的 The C++ Standard Library第 14 章专门讨论这个主题。
- Angelika Langer 和 Klaus Kreft 的 Standard C++ IOStreams and Locales写了一本书。
关于c++ - (w)ifstream 是否支持不同的编码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1274910/