Ответ 1
В Windows вы ДОЛЖНЫ использовать 8-битный ANSI (и он должен соответствовать языку пользователя) или UTF16 для имен файлов, другой доступной опции нет. Вы можете продолжать использовать string
и UTF8 в своем основном коде, но вам придется конвертировать имена файлов UTF8 в UTF16 при открытии файлов. Менее эффективно, но это то, что вам нужно сделать.
К счастью, реализация VC++ std::ifstream
и std::ofstream
имеет нестандартные перегрузки своих конструкторов и методов open()
для принятия строк wchar_t*
для имен файлов UTF16.
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
);
Вам придется использовать #ifdef
для обнаружения компиляции Windows (к сожалению, разные компиляторы C++ идентифицируют это по-разному) и временно преобразовывать строку UTF8 в UTF16 при открытии файла.
#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;
}
Обратите внимание, что это гарантированно работает только в VC++. Другие компиляторы C++ для Windows не гарантируют аналогичных расширений.