使用纯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月最少两年。
不幸的是,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