【问题标题】:Reading From A File Which Contains Unicode Characters从包含 Unicode 字符的文件中读取
【发布时间】:2012-11-21 17:40:18
【问题描述】:

我有一个巨大的文件,其中包含开头的 unicode 字符串(第一个 ~10,000 个字符左右) 我不关心 unicode 部分,我感兴趣的部分不是 unicode,但每当我尝试读取这些部分时,我都会得到'=',如果我要将整个文件加载到 char 数组并写入一些带有ofstream 的临时文件(不更改数据)我得到的数据不正确实际上我得到的只是一个填充有Í 的文本文件如果我要手动删除unicode 部分一切正常,所以看起来ifstream 无法处理使用包含 unicode 数据的流,但如果这个假设成立,有没有办法处理这个文件,将新库引入我的项目?

谢谢,

编辑:这是一个示例代码,程序从这个文件中读取,其中包含不能用 ASCII 表示的字符(一些,不是全部)。

ifstream inFile("somefile");
inFile.seekg(0,ios_base::end);
size_t size = inFile.tellg();
inFile.seekg(0,ios_base::beg);
char *book = new  char[size];
inFile.read(book,size);
for (int i = 0; i < size; i++) {
  cout << book[i] << " " << i << endl; //book[i] will always be '='
}
ofstream outFile("TEST.txt");
outFile.write(book,size);
outFile.close();

【问题讨论】:

  • 有许多 Unicode 库能够读取此类文件。 (例如 Qt 内部或 GTK 的 Glib 内部)。
  • 是的,我知道我可以使用 Qt,但我不想在我的项目中引入新库。另外,我不关心unicode部分我只关心unicode字符之后的部分(可以用ASCII表示的部分)
  • 文件使用 Unicode 的几种表示形式(UTF-8、UTF-16、UTF-32 等)中的哪一种?
  • "如果这个假设为真" --- 根据您的平台、编译器和 Unicode 表示(UTF-8 等),该假设可能正确,也可能不正确。分享以上部分或全部内容会有所帮助。
  • 它使用 UTF-8,但我也带有 ANSI 版本(不适用于 ifstream)

标签: c++ unicode ascii iostream ifstream


【解决方案1】:

Keith Thompson 的问题非常重要。根据哪种 Unicode 编码,编写一个读取(并丢弃)Unicode 字符的小型 C 例程可能很简单,也可能稍微复杂一些。

假设编码是 UTF-8,您将无法确定何时停止丢弃,因为 ASCII 是 UTF-8 的子集,所以每当您遇到 ASCII 字符时,您可能会想说“就是这样,我们又回到了 ASCII 领域”,而下一个字符可能仍在 ASCII 范围之外。

所以你需要读取文件并确定最后一个字符>127 在哪里。之后的任何内容都是纯 ASCII ——希望如此。

【讨论】:

  • 感谢您的回答,我真正不明白的是,当文件中有非 ASCII 字符时,ifstream 如何无法读取 ASCII。因为据我所知,UTF-8 与 ASCII 兼容(前 255 个字符具有相同的 int 表示形式),但可惜的是,使用 ifstream 读取文件并使用 ofstream 螺丝保存文件中的每个字符。
  • 实际上,ASCII 与 UTF-8 兼容——前 128 个码点相同——但 UTF-8 与 ASCII 不兼容。任何高于 127/0x7F 的都不是 ASCII。
  • 是的,你是对的,对不起,这就是我的意思,但我仍然没有得到正确的结果如果我使用 Qt 那么我没有任何问题(QString 支持 unicode 字符)。但我不明白为什么 cout 无法打印数组中的所有内容(无论它们是否可以用 ASCII 表示)只要我有一个不能用 ASCII 表示的字符我会得到每个字符的“=” . (一旦删除开头的 Unicode 字符,我就会得到正确的结果。)
【解决方案2】:

文本文件通常只有一种编码 utf-8、utf-16(大端或小端)或 utf-32(大或小)或 ASCII 或其他 ANSI 代码页。混合编码只能通过一些自定义方式实现。

也就是说,您必须以相同的编码读取所需的数据和不需要的数据。如果您知道格式是 utf-8,则可以根据您要对数据执行的操作,将文件作为二进制文件逐个读取到 char 缓冲区中。然后,您可以使用类似 strnextc 的 API(在 Windows 上。等效的 API 必须在其他平台上可用)在缓冲区中逐个字符地移动。一旦你到达终点 - 你可以将天平移动到缓冲区的前面并从文件中加载缓冲区的其余部分。

事实上,您通常可以将上述方法用于任何编码。但是对于 utf-16,您可以尝试使用 wifstream - 只要文件的字节顺序和您将运行的平台相同。并且您需要检查 wifstream 的实现是否擅长处理 endiness 的变化并且能够处理 BOM(字节顺序标记) - 通常存在于的 2 字节序列(“FE FF”或“FF FE”)文件的开头 - 不用管代理对。

【讨论】:

    猜你喜欢
    • 2012-02-04
    • 1970-01-01
    • 1970-01-01
    • 2017-02-08
    • 2019-03-18
    • 2018-08-09
    • 2016-12-08
    • 2018-06-22
    相关资源
    最近更新 更多