STL и UTF-8 файл ввода / вывода. Как это сделать?

Я использую wchar_t для внутренних строк и UTF-8 для хранения в файлах. Мне нужно использовать STL для ввода / вывода текста на экран, а также сделать это с помощью полной литовской кодировки.
Это все нормально, потому что я не обязан делать то же самое для файлов, поэтому следующий пример отлично справляется со своей задачей:

#include <io.h>
# include 
# включить 
    _setmode (_fileno(stdout), _O_U16TEXT);
    wcout << L"AaĄąfl" << endl;
Но мне стало любопытно, и я попытался сделать то же самое с файлами, но безуспешно. Конечно, я мог бы использовать форматированный ввод / вывод, но это... не рекомендуется.
    FILE* fp;
    _wfopen_s (&fp, L"utf-8_out_test.txt", L"w");
    _setmode (_fileno (fp), _O_U8TEXT);
    _fwprintf_p (fp, L"AaĄą\nfl");
    fclose (fp);
    _wfopen_s (&fp, L"utf-8_in_test.txt", L"r");
    _setmode (_fileno (fp), _O_U8TEXT);
    wchar_t text[256];
    fseek (fp, NULL, SEEK_SET);
    fwscanf (fp, L"%s", text);
    wcout << text << endl;
    fwscanf (fp, L"%s", text);
    wcout << text << endl;
    fclose (fp);
Этот фрагмент отлично работает (хотя я не уверен, как он обрабатывает неправильно сформированные символы). Итак, есть ли способ:

  • получить FILE* или целочисленный дескриптор файла формирует std::basic_*fstream?
  • моделировать _setmode () в теме?
  • простираться std::basic_*fstream так он обрабатывает ввод / вывод UTF-8?

Да, я учусь в университете, и это в некоторой степени связано с моими заданиями, но я пытаюсь понять это для себя. Это не повлияет на мою оценку или что-то в этом роде.

5 ответов

Решение

Используйте шаблон std:: codecvt_facet для выполнения преобразования.

Вы можете использовать стандартную std::codecvt_byname или нестандартную реализацию codecvt_facet.

#include <locale>
using namespace std;
typedef codecvt_facet<wchar_t, char, mbstate_t> Cvt;
locale utf8locale(locale(), new codecvt_byname<wchar_t, char, mbstate_t> ("en_US.UTF-8"));
wcout.pubimbue(utf8locale);
wcout << L"Hello, wide to multybyte world!" << endl;

Помните, что на некоторых платформах codecvt_byname может выполнять преобразование только для локалей, установленных в системе.

Ну, после некоторого тестирования я понял, что FILE принимается за _iobufw*fstream конструктор). Итак, следующий код делает то, что мне нужно.

# включить 
# включить 
# включить 
# include 
//Для записи
    FILE* fp;
    _wfopen_s (&fp, L"utf-8_out_test.txt", L"w");
    _setmode (_fileno (fp), _O_U8TEXT);
    wofstream fs (fp);
    fs << L"ąfl";
    fclose (fp);
// И читаю
    FILE* fp;
    _wfopen_s (&fp, L"utf-8_in_test.txt", L"r");
    _setmode (_fileno (fp), _O_U8TEXT);
    wifstream fs (fp);
    массив wchar_t [6];
    fs.getline (массив, 5);
    wcout << array << endl;// Для отладки
    fclose (fp); 
Этот пример читает и записывает легальные файлы UTF-8 (без BOM) в Windows, скомпилированные с Visual Studio 2k8.

Может кто-нибудь дать какие-либо комментарии по поводу переносимости? Улучшения?

Самым простым способом было бы сделать преобразование в UTF-8 самостоятельно, прежде чем пытаться выводить. Вы можете получить некоторое вдохновение от этого вопроса: UTF8 в / из широкого преобразования символов в STL

получить FILE* или целочисленный дескриптор файла формы std::basic_*fstream?

Ответил в другом месте.

Вы не можете заставить STL напрямую работать с UTF-8. Основная причина в том, что STL косвенно запрещает использование символов, состоящих из нескольких символов. Каждый символ должен быть один символ / wchar_t.

Microsoft фактически нарушает стандарт своей кодировкой UTF-16, так что, возможно, вы можете получить вдохновение там.

Другие вопросы по тегам