Вопрос по utf-8, c++, unicode, windows, fstream – fstream :: open () Unicode или не-Ascii символы не работают (с std :: ios :: out) в Windows

3

В проекте C ++ я хочу открыть файл (fstream::open()) (что, кажется, является серьезной проблемой). Сборка Windows моей программы с треском провалилась.

File "ä" (UTF-8 0xC3 0xA4)

<code>std::string s = ...;
//Convert s
std::fstream f;
f.open(s.c_str(), std::ios::binary | std::ios::in); //Works (f.is_open() == true)
f.close();
f.open(s.c_str(), std::ios::binary | std::ios::in | std::ios::out); //Doesn't work
</code>

The string s is UTF-8 encoded, but then converted from UTF-8 to Latin1 (0xE4). I'm using Qt, so QString::fromUtf8(s.c_str()).toLocal8Bit().constData().

Why can I open the file for reading, but not for writing?

File "и" (UTF-8 0xD0 0xB8)

Same code, doesn't work at all.

Кажется, этот символ не подходит для кодировки Windows-1252. Как я могу открыть такой fstream (я не использую MSVC, поэтомунетfstream::open(const wchar_t*, ios_base::openmode))?

Ваша стандартная библиотека C и C ++ должна поддерживать Unicode (то есть они должны преобразовать свои входные строки UTF-8 в UTF-16 и затем вызватьCreateFileW). Если это не так, вам не повезло & # x2013; вам тогда наверное нужно позвонитьCreateFileW непосредственно. Philipp
@ Adam Rosenfield Я использую mingw32-g ++ - 4.6.2. _wfopen () возвращает указатель FILE *, как мне открыть объект fstream таким образом? basic6
Какой компилятор и библиотеку C вы используете? Если вы, например, используете MinGW, вы все равно можете использовать функции из CRT MS, такие как_wfopen, Если вы используете другую среду выполнения C (например, libc Cygwin GCC), то вы зависите от поддержки Unicode этой библиотеки времени выполнения. Adam Rosenfield
@ basic6: я, к сожалению, не знаю, есть ли способ сделать это. Здесьstd::wfstream класс, но егоopen Метод также занимает толькоconst char* для имени файла. Если вы хотите иметь возможность открывать имена файлов Unicode, вам нужно либо использовать библиотеку stdio C, либо полностью буферизовать данные файла, считав их все в память и используяstd::stringstream разобрать данные. Adam Rosenfield
Я думаю, что имена файлов в Windows должны быть в кодировке UTF-16, и вам нужно использовать специальные функции обработки файлов Windows (_wfopenи т. д.) для доступа к файлам по их длинному имени. В качестве альтернативы вы можете использовать короткое имя. Kerrek SB

Ваш Ответ

2   ответа
3

В реализациях Microsoft STL существует нестандартное расширение (перегрузка), позволяющее поддерживать юникод для строк в кодировке UTF-16.

Просто передайте std :: wstring в кодировке UTF-16 в fstream :: open (). Это единственный способ заставить его работать с fstream.

Вы можете прочитать больше о том, что я считаю самым простым способом поддержки Unicode в Windows здесь:http://utf8everywhere.org/

@ basic6: пожалуйста, прочитайтеconversion funciotns раздел. AFAIK библиотека nowide должна работать и на MinGW.
Это, вероятно, подходящее решение, но AFAIK эта перегрузка доступна только с MSVC, а не с MinGW («нет функции соответствия для вызова ...»). И я не использую компилятор Microsoft, потому что я не перенес код, над которым я сейчас работаю, на Microsoft C ++ (иными словами, код не скомпилируется, и я пока не удосужился найти его). почему). basic6
3

Используя стандартные API (такие как std :: fstream) в Windows, вы можете открыть файл только в том случае, если имя файла можно закодировать с использованием установленной в данный момент & quot; ANSI Codepage & quot; (CP_ACP).

Это означает, что могут быть файлы, которые просто невозможно открыть с помощью этих API в Windows. Если Microsoft не реализует поддержку для установки CP_ACP в CP_UTF8, то это не может быть с помощью реализации стандартной библиотеки Microsoft CRT или C ++.

(В Windows была функция под названием «короткие» имена файлов, где при включении у каждого файла на диске было имя файла ASCII, которое можно использовать через стандартные API. Однако эта функция исчезает, поэтому она не представляет собой жизнеспособное решение.)

Похожие вопросы