On Windows, you MUST use 8-bit ANSI (and it must match the user's language) or UTF16 for file names, there is no other option available. You can continue to use string and UTF8 in your main code, but you will have to convert the UTF8 file names to UTF16 when opening the files. Less effective, but this is what you need to do.
Fortunately, the VC ++ implementation std::ifstream and std::ofstream has non-standard overloads of its constructors and open() methods to accept wchar_t* strings for UTF16 file names.
explicit basic_ifstream( const wchar_t *_Filename, ios_base::openmode _Mode = ios_base::in, int _Prot = (int)ios_base::_Openprot ); void open( const wchar_t *_Filename, ios_base::openmode _Mode = ios_base::in, int _Prot = (int)ios_base::_Openprot ); void open( const wchar_t *_Filename, ios_base::openmode _Mode );
explicit basic_ofstream( const wchar_t *_Filename, ios_base::openmode _Mode = ios_base::out, int _Prot = (int)ios_base::_Openprot ); void open( const wchar_t *_Filename, ios_base::openmode _Mode = ios_base::out, int _Prot = (int)ios_base::_Openprot ); void open( const wchar_t *_Filename, ios_base::openmode _Mode );
You will have to use #ifdef to detect Windows compilation (unfortunately, different C ++ compilers identify this differently) and temporarily convert the UTF8 string to UTF16 when opening the file.
#ifdef _MSC_VER std::wstring ToUtf16(std::string str) { std::wstring ret; int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), NULL, 0); if (len > 0) { ret.resize(len); MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), &ret[0], len); } return ret; } #endif int main() { std::string utf8path = ...; std::ifstream iFileStream( #ifdef _MSC_VER ToUtf16(utf8path).c_str() #else utf8path.c_str() #endif , std::ifstream::in | std::ifstream::binary); ... return 0; }
Please note that this is guaranteed to work only in VC ++. Other C ++ compilers for Windows do not guarantee similar extensions.