Открытие входного файлового потока с именем Unicode, но данными ASCII

0

Я компилирую свою библиотеку с поддержкой unicode, и теперь у меня возникла проблема в том, что мне нужно открыть файл данных, который находится в ASCII, но, конечно, имя файла имеет широкие диалоги. Итак, как бы я это сделал?

Когда я использую этот код:

std::wstring s = L"path";
std::ifstream fl;
fl.open(s.c_str(), std::fstream::in);

то я получаю эту ошибку:

error: no matching function for call to 'std::basic_ifstream<char>::open(const wchar_t*, const openmode&)'

И когда я использую

std::wifstream fl;
fl.open(s.c_str(), std::fstream::in);

Я получаю ту же ошибку (???)

error: no matching function for call to 'std::basic_ifstream<wchar_t>::open(const wchar_t*, const openmode&)'

Тем не менее, когда я буду использовать std::wifstream, std::wifstream ли поток входные данные в unicode? Если это так, тогда мне придется использовать std::ifstream но мне все равно нужно передать ему широкую строку или каким-то образом преобразовать ее в ASCII. Каков правильный способ сделать это?

Я использую MingW gcc 4.8.3.

mingw32-g++.exe -pedantic -std=c++11 -Wextra -Wall -g -D_UNICODE -D_WIN32 -Iinclude -c propertyfile.cpp -o propertyfile.o
Теги:
unicode
g++

4 ответа

-2
Лучший ответ

Что-то вроде этого:

std::wstring s = L"path";
std::string ansi( begin(s), end(s) );
std::ifstream fl ( ansi );

Если файл ASCII, вы не можете использовать wifstream.

Заметьте, что он работает только в том случае, если путь является чистым ASCII.

  • 1
    Почему это было отвергнуто? Это неправильное преобразование, или это только из-за неправильных скобок?
  • 0
    Я не знаю, это вполне законный код C ++ 11. coliru.stacked-crooked.com/a/ab322f7b56e94c71
Показать ещё 14 комментариев
2

Для решения этой проблемы нет простого решения. У меня есть две идеи для этого:

  1. Попробуйте создать свой собственный файловый поток buf с помощью _wfopen.
  2. Используйте boost-library. Boost.Filesystem
  • 1
    +1. К сожалению, имена файлов Windows указываются в единицах кода UTF-16 ( wchar в Windows), а имена файлов Unix указываются в байтах ( char , обычно интерпретируемый как UTF-8 в современном Linux / OSX). Вы должны переключаться между байтово-ориентированными вызовами стандартной библиотеки C и специфичными для Windows вызовами (например, _wfopen или прямыми эквивалентами Win32 API, такими как OpenFileW ) в зависимости от платформы, на которой вы работаете, что печально. (Или, как уже упоминалось, используйте библиотеку, которая делает это за вас.)
  • 1
    +1, этот ответ намного лучше принятого.
0

std::ifstream - это просто std::istream с простым способом установить файл в качестве цели. Поскольку он не позволяет UTF-8, вы должны установить файл по-другому. Если посмотреть на конструкторы std::streambuf вы должны заметить std::streambuf (который также можно установить/заменить rdbuf). Теперь вы не могли бы написать свой собственный streambuf производного класса, который использует _wfopen, но нет необходимости: MinGW имеет расширение, называемое __gnu_cxx::stdio_filebuf (#include <ext/stdio_filebuf.h>).

Из источника:

  /**
   *  @param  __fd  An open file descriptor.
   *  @param  __mode  Same meaning as in a standard filebuf.
   *  @param  __size Optimal or preferred size of internal buffer,
   *                 in chars.
   *
   *  This constructor associates a file stream buffer with an open
   *  POSIX file descriptor. The file descriptor will be automatically
   *  closed when the stdio_filebuf is closed/destroyed.
  */
  stdio_filebuf(int __fd, std::ios_base::openmode __mode,
        size_t __size = static_cast<size_t>(BUFSIZ));

  /**
   *  @param  __f  An open @c FILE*.
   *  @param  __mode  Same meaning as in a standard filebuf.
   *  @param  __size Optimal or preferred size of internal buffer,
   *                 in chars.  Defaults to system @c BUFSIZ.
   *
   *  This constructor associates a file stream buffer with an open
   *  C @c FILE*.  The @c FILE* will not be automatically closed when the
   *  stdio_filebuf is closed/destroyed.
  */
  stdio_filebuf(std::__c_file* __f, std::ios_base::openmode __mode,
        size_t __size = static_cast<size_t>(BUFSIZ));

Ваша единственная работа - перевести std::ios_base::openmode в режим для файлового дескриптора или указателя файла. FILE* не передает свое владение, поэтому вам все равно придется заботиться об этом, но std::unique_ptr с функцией закрытия файла как deleter, связанной каким-либо образом с вашим stdio_filebuf, тоже решает.

MSVC поддерживает имена файлов Unicode с помощью std::wifstream (utf-8 для преобразования utf-16 с помощью MultiByteToWideChar), Clang совместим с MinGW.

Написание кросс-платформенного класса fstream теперь легко. Прежде всего: вывод из std::fstream. В Unix ваш класс должен выглядеть как std::fstream, поэтому вам просто нужно скопировать конструкторы (С++ 11 way: using std::fstream::fstream;). В Windows вам нужно реализовать конструкторы (которые просто вызывают open) и переопределить открытые функции-члены (в конце все просто переходит к одной открытой функции, где лежит работа, не более того).

-1

Попробуй это:

fl.open(s.c_str(), std::ios_base::in);

Я не уверен в mingw32-g++, но вы должны использовать ios_base в компиляторе MS. Что касается данных, которые он ожидает - да, он будет ожидать unicode или ansi в зависимости от типа, но только если вы прочитаете его как текст. Прочитайте его как двоичные данные, а затем просто скопируйте в свой массив ansi, и вы получите ansi-текст из файла Unicode.

  • 0
    Оператор спрашивает о случае, когда имя файла UTF-8. Ваше решение не может открыть имя файла в кодировке UTF-8.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню