14

当我使用 wifstream 将文本文件读取为宽字符串 (std::wstring) 时,流实现是否支持不同的编码 - 即它可以用于读取例如 ASCII、UTF-8 和 UTF-16 文件吗?

如果没有,我该怎么办?

(我需要阅读整个文件,如果有区别的话)

4

3 回答 3

23

C++ 通过std::locale和 facet支持字符编码std::codecvt。一般的想法是,一个locale对象描述了系统的各个方面,这些方面可能因文化而异,(人类)语言因语言而异。这些方面被分解为facets,它们是模板参数,定义了如何构造依赖于本地化的对象(包括 I/O 流)。当您从 a 读取istream或写入 aostream时,每个字符的实际写入都会通过语言环境的方面进行过滤。这些方面不仅涵盖了 Unicode 类型的编码,还涵盖了诸如如何写入大数字(例如使用逗号或句点)、货币、时间、大小写以及大量其他细节等各种特性。

然而,仅仅因为存在进行编码的工具并不意味着标准库实际上可以处理所有编码,也不意味着这些代码可以简单地正确执行。即使是你应该读入的字符大小(更不用说编码部分)这样基本的东西也很困难,因为wchar_t它可能太小(破坏你的数据)或太大(浪费空间),以及最常见的编译器(例如Visual C++ 和 Gnu C++)在实现的规模上确实有所不同。所以你一般需要找外部库来做实际的编码。

  • iconv通常被认为是正确的,但很难找到如何将其绑定到 C++ 机制的示例。
  • jla3ep 提到 了 libICU,它非常彻底,但C++ API并没有尝试与标准很好地配合(据我所知:您可以扫描示例以查看是否可以做得更好。)

我能找到的涵盖所有基础的最直接示例来自 Boost 的UTF-8 codecvt facet,其中一个示例专门尝试对 UTF-8 (UCS4) 进行编码以供 IO 流使用。它看起来像这样,尽管我不建议逐字复制它。需要更多地挖掘源代码才能理解它(我不声称):

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),请查看以下内容:

于 2009-08-13T23:33:28.560 回答
3

ifstream不关心文件的编码。它只是从文件中读取字符(字节)。wifstream读取宽字节(wchar_t),但它仍然对文件编码一无所知。wifstream对于 UCS-2 来说已经足够好了——Unicode 的固定长度字符编码(每个字符用两个字节表示)。

您可以使用 IBM ICU库来处理 Unicode 文件。

Unicode 国际组件 (ICU) 是一套成熟的、可移植的 C/C++ 和 Java 库,用于支持 Unicode、软件国际化 (I18N) 和全球化 (G11N),在所有平台上为应用程序提供相同的结果。

ICU 是根据非限制性开源许可证发布的,该许可证适用于商业软件和其他开源或免费软件。

于 2009-08-13T22:31:46.960 回答
0

宽字符串和宽字符流的设计早于 UTF-8、UTF-16 和 Unicode。如果你想获得技术,标准字符串和标准流不一定在 ASCII 上运行(只是基本上所有的计算机都使用 ASCII;你可能有一台 EBCDIC 机器)。

Raymond Chen 曾经写过一个系列来说明如何使用不同的宽字符流/字符串类型

于 2009-08-13T22:27:29.467 回答