2014-01-30 2 views
0

Я компилирую свою библиотеку с поддержкой unicode, и теперь у меня возникла проблема в том, что мне нужно открыть файл данных, который находится в ASCII, но, конечно, имя файла с widechars. Итак, как бы я это сделал?Открытие входного потока с именем юникода, но данные 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::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 

ответ

-1

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

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

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

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

+1

Почему это было приостановлено? Является ли неправильное преобразование, или это просто из-за неправильных фигурных скобок? – Devolus

+0

Я не знаю, это вполне законный код C++ 11. http://coliru.stacked-crooked.com/a/ab322f7b56e94c71 – galop1n

+0

Поскольку каждый аспект ответа неверен? – Simple

-1

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

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

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

+0

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

2

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

  1. Попробуйте создать свой собственный файловый поток БУФ с _wfopen.
  2. Используйте boost-library. Boost.Filesystem
+1

+1.Это печально, но имена файлов Windows указаны в терминах кодовых блоков UTF-16 ('wchar' в Windows), а имена файлов Unix указаны в байтах (' char', обычно интерпретируемый как UTF-8 в современной Linux/OSX) , Вы должны переключаться между стандартными библиотечными вызовами, ориентированными на байты, и вызовами, специфичными для Windows (например, '_wfopen' или прямыми эквивалентами API Win32, такими как' OpenFileW'), в зависимости от платформы, на которой вы работаете, что печально. (Или, как уже упоминалось, используйте библиотеку, которая сделает это для вас.) – bobince

+1

+1, этот ответ намного лучше, чем принятый. – Philipp

0

std::ifstream просто std::istream простой способ установить файл в качестве цели. Поскольку он не позволяет UTF-8, вы должны установить файл по-другому. Посмотрев на istream constructors, вы должны заметить 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's @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, поэтому вам просто нужно скопировать конструкторы (C++ 11 way: using std::fstream::fstream;). В Windows вы должны реализовать конструкторы (которые просто вызывают open) и переопределить open функции-члены (в конце все просто переходит к одной открытой функции, где лежит работа, не более).

Смежные вопросы