使用纯C ++ / Boost读取/写入带unicode文件名的文件

我想使用boost文件系统读取/写入一个带unicode文件名的文件,在Windows上使用boost语言环境(mingw)(最后应该与平台无关)。

这是我的代码:

#include <boost/locale.hpp>
#define BOOST_NO_CXX11_SCOPED_ENUMS
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
namespace fs = boost::filesystem;

#include <string>
#include <iostream>

int main() {

  std::locale::global(boost::locale::generator().generate(""));
  fs::path::imbue(std::locale());

  fs::path file("äöü.txt");
  if (!fs::exists(file)) {
    std::cout << "File does not exist" << std::endl;
  }

  fs::ofstream(file, std::ios_base::app) << "Test" << std::endl;
}

fs::exists确实检查名称为äöü.txt的文件。 但是这个书面文件的名字是äöü.txt

阅读给出了同样的问题。 使用fs::wofstream也没有帮助,因为fs::wofstream处理宽输入。

我怎样才能解决这个使用C + + 11和提升?

编辑:发布错误报告:https://svn.boost.org/trac/boost/ticket/9968

为了澄清恩惠: Qt非常简单,但我想要一个跨平台的解决方案,只使用C ++ 11和Boost,不需要Qt,也不需要ICU。


这可能很复杂,原因有两个:

  • C ++源文件中有一个非ASCII字符串。 如何将此文字转换为const char *的二进制表示形式取决于编译器设置和/或OS代码页设置。

  • Windows只能通过UTF-16编码使用Unicode文件名,而Unix使用UTF-8作为Unicode文件名。

  • 构造路径对象

    为了在Windows上实现这个功能,你可以尝试将你的文字改为宽字符(UTF-16):

    const wchar_t *name = L"u00E4u00F6u00FC.txt";
    fs::path file(name);
    

    要获得完整的跨平台解决方案,您必须以UTF-8或UTF-16字符串开头,然后确保将其正确转换为path::string_type类。

    打开文件流

    不幸的是,C ++(因此Boost) ofstream API不允许指定wchar_t字符串作为文件名。 构造函数和open方法都是这种情况。

    您可以尝试确保路径对象不会立即转换为const char * (通过使用C ++ 11字符串API),但这可能无济于事:

    std::ofstream(file.native()) << "Test" << std::endl;
    

    要使Windows工作,您可能需要调用支持Unicode的Windows API, CreateFileW ,将HANDLE转换为FILE * ,然后使用FILE *作为ofstream构造函数。 这在另一个StackOverflow的答案都说明,但我不知道这ofstream构造函数将存在于MinGW的。

    不幸的是, basic_ofstream似乎不允许自定义basic_filebuf类型的子类化,所以FILE *转换可能是唯一的(完全不可移植的)选项。

    另一种方法是:内存映射文件

    您也可以使用内存映射I / O写入文件,而不是使用文件流。 根据Boost实现的方式(它不是C ++标准库的一部分),该方法可以与Windows Unicode文件名一起使用。

    下面是一个使用path对象打开文件的提升示例(取自另一个答案):

    #include <boost/filesystem.hpp>
    #include <boost/iostreams/device/mapped_file.hpp>
    #include <iostream>
    
    int main()
    { 
      boost::filesystem::path p(L"b.cpp");
      boost::iostreams::mapped_file file(p); // or mapped_file_source
      std::cout << file.data() << std::endl;
    }
    

    我不知道这里的答案是如何被接受的,因为OP没有fs::path::imbue(std::locale()); 恰恰不是要给一个关于操作系统的代码页, std::wstring和什么不该。 否则,是的,他只是使用普通的老iconv,Winapi电话或其他建议在接受的答案。 但这不是在这里使用boost :: locale的要点

    真正的答案,为什么这不起作用,即使OP imbue()当前的区域,如Boost的文件中的说明(请参阅“默认编码Microsoft Windows下”),是因为升压(或MinGW的)是得不到解决的虫子截至2015年3月最少两年。

  • 问题#9968
  • 问题#9450
  • 问题#5769
  • 不幸的是,mingw用户似乎被冷落了。

    现在,开发人员为了掩盖这些错误而应该做的是一件完全不同的事情。 可能会发现他们需要精确地实现Dan所说的。


    您是否考虑过在源代码中使用ASCII字符并使用Boost.Locale库的Boost消息格式化功能使用ASCII密钥查找所需字符串的方法? http://www.boost.org/doc/libs/1_55_0/libs/locale/doc/html/messages_formatting.html

    或者,您可以使用Boost.Locale库来生成UTF-8库,然后使用“boost :: path :: imbue()”将该Boost.Path与该语言环境相混合。 http://boost.2283326.n4.nabble.com/boost-filesystem-path-as-utf-8-td4320098.html

    这也可能对你有用。

    Microsoft Windows下的默认编码http://www.boost.org/doc/libs/1_51_0/libs/locale/doc/html/default_encoding_under_windows.html

    链接地址: http://www.djcxy.com/p/54641.html

    上一篇: Read/Write file with unicode file name with plain C++/Boost

    下一篇: platform unicode in C/C++: Which encoding to use?