读取/写入具有纯C ++/Boost的Unicode文件名的文件 [英] Read/Write file with unicode file name with plain C++/Boost
问题描述
我想使用boost文件系统读写具有unicode文件名的文件,在Windows(mingw)上使用boost locale(最后应与平台无关).
I want to read / write a file with a unicode file name using boost filesystem, boost locale on Windows (mingw) (should be platform independent at the end).
这是我的代码:
#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
.
The fs::exists
really checks for a file with the name äöü.txt
.
But the written file has the name äöü.txt
.
阅读也有同样的问题.使用 fs :: wofstream
也不起作用,因为这只能处理广泛的输入.
Reading gives the same problem. Using fs::wofstream
doesn't help either, since this just handles wide input.
如何使用C ++ 11和Boost修复此问题?
How can I fix this using C++11 and boost?
已发布错误报告: https://svn.boost.org/trac/boost/ticket/9968
要澄清赏金,使用Qt相当简单,但是我希望使用仅C ++ 11和Boost,不使用Qt且不使用ICU的跨平台解决方案.
To clarify for the bounty: It is quite simple with Qt, but I would like a cross platform solution using just C++11 and Boost, no Qt and no ICU.
推荐答案
这可能很复杂,原因有两个:
This can be complicated, for two reasons:
-
您的C ++源文件中有一个非ASCII字符串.如何将该文字转换为
const char *
的二进制表示形式,将取决于编译器设置和/或OS代码页设置.
There's a non-ASCII string in your C++ source file. How this literal gets converted to the binary representation of a
const char *
would depend on compiler settings and/or OS codepage settings.
Windows仅通过UTF-16编码使用Unicode文件名,而Unix使用Unicode文件名使用UTF-8.
Windows only works with Unicode filenames through the UTF-16 encoding, while Unix uses UTF-8 for Unicode filenames.
构造路径对象
要在Windows上运行此功能,您可以尝试将文字更改为宽字符(UTF-16):
Constructing the path object
To get this working on Windows, you can try to change your literal to wide characters (UTF-16):
const wchar_t *name = L"\u00E4\u00F6\u00FC.txt";
fs::path file(name);
要获得完整的跨平台解决方案,您必须以UTF-8或UTF-16字符串开头,然后确保将其正确转换为 path :: string_type
课堂.
To get a full cross-platform solution, you'll have to start with either a UTF-8 or a UTF-16 string, then make sure it gets properly converted to the path::string_type
class.
不幸的是,C ++(因而是Boost)的 ofstream
API不允许将 wchar_t
字符串指定为文件名.构造函数和
Unfortunately, the C++ (and thus Boost) ofstream
API does not allow specifying wchar_t
strings as the filename. This is the case for both the constructor and the open
method.
您可以尝试确保路径对象不会立即转换为 const char *
(通过使用C ++ 11字符串API),但这可能无济于事:>
You could try to make sure that the path object does not get immediately converted to const char *
(by using the C++11 string API) but this probably won't help:
std::ofstream(file.native()) << "Test" << std::endl;
要使Windows正常运行,您可能必须调用支持Unicode的Windows API, ,但是我不确定该 ofstream
构造函数将存在于MinGW上.
For Windows to work, you might be able have to call the Unicode-aware Windows API, CreateFileW
, convert the HANDLE
to a FILE *
, then use the FILE *
for the ofstream
constructor. This is all described in another StackOverflow answer, but I'm not sure if that ofstream
constructor will exist on MinGW.
不幸的是, basic_ofstream
似乎不允许自定义 basic_filebuf
类型的子类化,因此 FILE *
转换可能是唯一的(完全非-便携式)选项.
Unfortunately basic_ofstream
doesn't seem to allow subclassing for custom basic_filebuf
types, so the FILE *
conversion might be the only (completely non-portable) option.
除了使用文件流之外,您还可以使用内存映射的I来写文件/O .根据Boost实现的方式(它不属于C ++标准库),此方法可以与Windows Unicode文件名一起使用.
Instead of using file streams, you can also write to files using memory-mapped I/O. Depending on how Boost implements this (it's not part of the C++ standard library), this method could work with Windows Unicode file names.
这是一个增强示例(取自另一个答案),该示例使用 path
对象来打开文件:
Here's a boost example (taken from another answer) that uses a path
object to open the file:
#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;
}
这篇关于读取/写入具有纯C ++/Boost的Unicode文件名的文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!