我遇到了升级文件流的问题:我需要在windows下的用户目录中创建和修改文件。但是,用户名包含一个变音符号,这使得在MinGW下编译时失败,因为标准缺少用于提升使用的文件流的wide_char open()API。请参阅Read/Write file with unicode file name with plain C++/Boost,UTF-8-compliant IOstreams和https://svn.boost.org/trac10/ticket/9968
但是我跑过这条线,这个问题主要发生在尝试使用系统代码页之外的字符时。在我的情况下,我只使用系统代码页中的字符,因为显然存在用户目录。这让我觉得,这应该有用,如果我能告诉boost :: path期望所有std::string
为UTF8,而是在调用string()
成员函数时将它们转换为系统编码(发生这种情况)在boost::fstream::open
)
基本上:有没有办法使用boost(和boost Locale)自动进行转换(UTF8->系统编码)?
这里要完成的是我设置语言环境的代码:
#ifdef _WIN32
// On windows we want to enforce the encoding (mostly UTF8). Also using "" would use the default which uses "wrong" separators
std::locale::global(boost::locale::generator().generate("C"));
#else
// In linux / OSX this suffices
std::locale::global(std::locale::classic());
#endif // _WIN32
// Use also the encoding (mostly UTF8) for bfs paths
bfs::path::imbue(std::locale());
答案 0 :(得分:1)
这是Windows上的一个问题,因为Windows使用的是UTF-16,而不是UTF-8。我经常使用这个功能来解决你的问题:
// get_filename_token.cpp
// Turns a UTF-8 filename into something you can pass to fstream::open() on
// Windows. Returns the argument on other systems.
// Copyright 2013 Michael Thomas Greer
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt )
#ifdef _WIN32
#include <string>
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
std::string get_filename_token( const std::string& filename )
{
// Convert the UTF-8 argument path to a Windows-friendly UTF-16 path
wchar_t* widepath = new wchar_t[ filename.length() + 1 ];
MultiByteToWideChar( CP_UTF8, 0, filename.c_str(), -1, widepath, filename.length() + 1 );
// Now get the 8.5 version of the name
DWORD n = GetShortPathNameW( widepath, NULL, 0 );
wchar_t* shortpath = new wchar_t[ n ];
GetShortPathNameW( widepath, shortpath, n );
// Convert the short version back to a C++-friendly char version
n = WideCharToMultiByte( CP_UTF8, 0, shortpath, -1, NULL, 0, NULL, NULL );
char* ansipath = new char[ n ];
WideCharToMultiByte( CP_UTF8, 0, shortpath, -1, ansipath, n, NULL, NULL );
std::string result( ansipath );
delete [] ansipath;
delete [] shortpath;
delete [] widepath;
return result;
}
#else
std::string get_filename_token( const std::string& filename )
{
// For all other systems, just return the argument UTF-8 string.
return filename;
}
#endif
(我已经删除了一些要发布的内容。)
答案 1 :(得分:1)
我找到了两个使用另一个库的解决方案,两个都有它们的缺点。
bfs::path
或宽字符串(Windows上的bfs::path
内部格式为UTF16)因此需要补丁,尽管它很简单。如果你想使用带有UTF8字符串的std::cout
等,也需要构建Windows(是的,它可以直接使用!)