【问题标题】:How to read a UCS-2 file?如何读取 UCS-2 文件?
【发布时间】:2012-07-25 05:51:11
【问题描述】:

我正在编写一个程序来获取 UCS-2 Little Endian 中 *.rc 文件编码中的信息。

int _tmain(int argc, _TCHAR* argv[]) {
  wstring csvLine(wstring sLine);
  wifstream fin("en.rc");
  wofstream fout("table.csv");
  wofstream fout_rm("temp.txt");
  wstring sLine;
  fout << "en\n";
  while(getline(fin,sLine)) {
    if (sLine.find(L"IDS") == -1)
      fout_rm << sLine << endl;
    else
      fout << csvLine(sLine);
  }
  fout << flush;
  system("pause");
  return 0;
}

“en.rc”中的第一行是#include &lt;windows.h&gt;,但sLine显示如下:

[0]     255 L'ÿ'
[1]     254 L'þ'
[2]     35  L'#'
[3]     0
[4]     105 L'i'
[5]     0
[6]     110 L'n'
[7]     0
[8]     99  L'c'
.       .
.       .
.       .

此程序可以正确处理 UTF-8。 UCS-2 怎么办?

【问题讨论】:

  • 您的示例代码甚至无法编译,因为它使用了未声明的变量fout_rm
  • 我粘贴的时候错过了声明行,代码已经更新了
  • 顺便说一下,此代码适用于 UTF-8 输入(类似的代码也不适用)。您可能很幸运,因为您只使用了前 127 个代码点中的字符。 C++ 流无法解码不同的编码,它们完全与编码无关。
  • 看起来您的“UCS-2 文件”实际上是一个带有 a byte-order marker 的 UTF-16 文件。

标签: c++ unicode encoding character-encoding wofstream


【解决方案1】:

宽流使用宽流缓冲区来访问文件。 Wide 流缓冲区从文件中读取字节,并使用其 codecvt facet 将这些字节转换为宽字符。默认的 codecvt facet 是std::codecvt&lt;wchar_t, char ,std::mbstate_t&gt;,它在wchar_tchar 的本机字符集之间进行转换(即,像mbstowcs( 一样)。

您没有使用本机 char 字符集,因此您需要一个将 UCS-2 读取为多字节序列并将其转换为宽字符的 codecvt facet。

#include <fstream>
#include <string>
#include <codecvt>
#include <iostream>

int main(int argc, char *argv[])
{
    wifstream fin("en.rc", std::ios::binary); // You need to open the file in binary mode

    // Imbue the file stream with a codecvt facet that uses UTF-16 as the external multibyte encoding
    fin.imbue(std::locale(fin.getloc(),
              new std::codecvt_utf16<wchar_t, 0xffff, consume_header>));

    // ^ We set 0xFFFF as the maxcode because that's the largest that will fit in a single wchar_t
    //   We use consume_header to detect and use the UTF-16 'BOM'

    // The following is not really the correct way to write Unicode output, but it's easy
    std::wstring sLine;
    std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> convert;
    while (getline(fin, sLine))
    {
        std::cout << convert.to_bytes(sLine) << '\n';
    }
}

请注意,UTF-16 存在问题。 wchar_t 的目的是让一个wchar_t 代表一个代码点。然而,Windows 使用 UTF-16 将一些代码点表示为 two wchar_ts。这意味着标准 API 在 Windows 上不能很好地工作。

这里的结果是,当文件包含代理对时,codecvt_utf16 将读取该对,将其转换为大于 16 位的单个代码点值,并且必须将值截断为 16 位以将其粘贴到 @ 987654334@。这意味着此代码实际上仅限于UCS-2。我已将 maxcode 模板参数设置为 0xFFFF 以反映这一点。

wchar_t 还存在许多其他问题,您可能希望完全避免它:What's “wrong” with C++ wchar_t?

【讨论】:

    【解决方案2】:
    #include <filesystem>
    namespace fs = std::filesystem;
    
        FILE* f = _wfopen(L"myfile.txt", L"rb");
        auto file_size = fs::file_size(filename);
    std::wstring buf;       
    buf.resize((size_t)file_size / sizeof(decltype(buf)::value_type));// buf in my code is a template object, so I use decltype(buf) to decide its type.
        fread(&buf[0], 1, 2, f); // escape UCS2 BOM
        fread(&buf[0], 1, file_size, f);
    

    【讨论】:

      猜你喜欢
      • 2020-01-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-30
      • 1970-01-01
      • 1970-01-01
      • 2013-06-09
      相关资源
      最近更新 更多