fstream::open():在Windows上,Unicode或非ASCII字符无法使用(用于std::ios::out)。

4
在一个C++项目中,我想要打开一个文件(fstream::open())(这似乎是一个主要问题)。我的程序在Windows构建时失败了。
  • File "ä" (UTF-8 0xC3 0xA4)

    std::string s = ...;
    //Convert s
    std::fstream f;
    f.open(s.c_str(), std::ios::binary | std::ios::in); //Works (f.is_open() == true)
    f.close();
    f.open(s.c_str(), std::ios::binary | std::ios::in | std::ios::out); //Doesn't work
    

    The string s is UTF-8 encoded, but then converted from UTF-8 to Latin1 (0xE4). I'm using Qt, so QString::fromUtf8(s.c_str()).toLocal8Bit().constData().

    Why can I open the file for reading, but not for writing?

  • File "и" (UTF-8 0xD0 0xB8)

    Same code, doesn't work at all.

似乎这个字符不适用于Windows-1252字符集。我该如何打开这样的fstream(我没有使用MSVC,因此没有 fstream :: open(const wchar_t *,ios_base :: openmode))?


1
我认为Windows中的文件名需要使用UTF-16编码,并且您需要使用特殊的Windows文件处理函数(例如_wfopen等)通过其长名称访问文件。或者,您可以使用短名称。 - Kerrek SB
2
你使用的编译器和C库是什么?如果你使用的是MinGW,你仍然可以使用MS CRT中的函数,比如_wfopen。如果你使用的是不同的C运行时库(比如Cygwin GCC的libc),那么你就要看这个运行时库的Unicode支持了。 - Adam Rosenfield
您的 C 和 C++ 标准库需要支持 Unicode(即它们必须将其 UTF-8 输入字符串转换为 UTF-16,然后调用 CreateFileW)。如果它们不支持,您就需要直接调用 CreateFileW - Philipp
@Adam Rosenfield 我正在使用mingw32-g++-4.6.2。_wfopen()返回一个FILE*指针,我该如何以这种方式打开一个fstream对象? - basic6
@basic6:很遗憾,我不知道是否有方法可以做到这一点。有std::wfstream类,但它的open方法也只接受文件名的const char*。如果您想要能够打开Unicode文件名,则需要使用C的stdio库,或者完全缓冲文件数据将其全部读入内存,并使用std::stringstream来解析数据。 - Adam Rosenfield
长篇回答短评:请参考http://utf8everywhere.org/了解如何正确处理。 - Pavel Radzivilovsky
2个回答

4
使用标准的API(例如std :: fstream)在Windows上,您只能打开可以使用当前设置的“ANSI Codepage”(CP_ACP)进行编码的文件名。
这意味着在Windows上可能会有一些无法使用这些API打开的文件。除非Microsoft实现对将CP_ACP设置为CP_UTF8的支持,否则无法使用Microsoft的CRT或C ++标准库实现此操作。
(Windows拥有一个名为“short”文件名的功能,当启用时,驱动器上的每个文件都具有ASCII文件名,可以通过标准API使用。但是,此功能正在消失,因此不表示可行的解决方案。)
更新:Windows 10已添加了将代码页设置为UTF-8的支持。

4
在Microsoft的STL实现中,有一个非标准扩展(重载),允许对UTF-16编码的字符串进行Unicode支持。
只需将UTF-16编码的std::wstring传递给fstream::open()。这是使其与fstream配合使用的唯一方法。
您可以在此处阅读更多关于我发现的在Windows上支持Unicode的最简单方法:http://utf8everywhere.org/

这可能是适当的解决方案,但据我所知,这种重载仅在MSVC中可用,而不是在MinGW中(“没有匹配的函数调用…”)。而且我不使用微软的编译器,因为我还没有将我目前正在工作的代码移植到微软的C++上(换句话说,代码无法编译,我还没有找出原因)。 - basic6
1
@basic6:请阅读转换函数部分。据我所知,nowide库也应该在MinGW上运行。 - Yakov Galka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接