fstream::open() Unicode или символы, отличные от Ascii, не работают (с std::ios::out) в Windows

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

  • Файл "ä" (UTF-8 0xC3 0xA4)

    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
    

    Строка s имеет кодировку UTF-8, но затем преобразуется из UTF-8 в Latin1 (0xE4). Я использую Qt, поэтому QString::fromUtf8(s.c_str()).toLocal8Bit().constData().

    Почему я могу открыть файл для чтения, но не для записи?

  • Файл "и" (UTF-8 0xD0 0xB8)

    Тот же код, вообще не работает.

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


person basic6    schedule 12.05.2012    source источник
comment
Я думаю, что имена файлов в Windows должны быть закодированы в кодировке UTF-16, и вам нужно использовать специальные функции обработки файлов Windows (_wfopen и т. д.) для доступа к файлам по их длинному имени. В качестве альтернативы вы можете использовать короткое имя.   -  person Kerrek SB    schedule 13.05.2012
comment
Какой компилятор и библиотеку C вы используете? Если вы используете, скажем, MinGW, вы все равно можете использовать функции из MS CRT, такие как _wfopen. Если вы используете другую среду выполнения C (например, libc Cygwin GCC), то вы зависите от поддержки Unicode в этой библиотеке времени выполнения.   -  person Adam Rosenfield    schedule 14.05.2012
comment
Ваша стандартная библиотека C и C++ должна поддерживать Unicode (т. е. они должны преобразовать свои входные строки UTF-8 в UTF-16, а затем вызвать CreateFileW). Если они этого не сделают, вам не повезло — тогда вам, вероятно, нужно вызвать CreateFileW напрямую.   -  person Philipp    schedule 17.05.2012
comment
@ Адам Розенфилд Я использую mingw32-g++-4.6.2. _wfopen() возвращает указатель FILE*, как мне таким образом открыть объект fstream?   -  person basic6    schedule 18.05.2012
comment
@basic6: к сожалению, я не знаю, есть ли способ сделать это. Существует класс std::wfstream, но его метод open также принимает только const char* для имени файла. Если вы хотите иметь возможность открывать имена файлов в формате Unicode, вам нужно либо использовать библиотеку C stdio, либо полностью буферизовать данные файла, прочитав их все в память и используя std::stringstream для анализа данных.   -  person Adam Rosenfield    schedule 18.05.2012
comment
Длинный ответ на короткий комментарий: см. utf8everywhere.org о том, как это сделать правильно.   -  person Pavel Radzivilovsky    schedule 29.11.2014


Ответы (2)


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

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

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

person Pavel Radzivilovsky    schedule 14.05.2012

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

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

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

Обновление: в Windows 10 добавлена ​​поддержка установки кодовой страницы на UTF-8.

person bames53    schedule 13.05.2012