(w)ifstream поддерживает разные кодировки
Когда я читаю текстовый файл в строку широких символов (std::wstring), используя wifstream, поддерживает ли реализация потока разные кодировки - то есть может ли он использоваться для чтения, например, файлов ASCII, UTF-8 и UTF-16?
Если нет, то что мне делать?
(Мне нужно прочитать весь файл, если это имеет значение)
3 ответа
C++ поддерживает кодировки символов с помощью std::locale
и аспект std::codecvt
, Общая идея заключается в том, что locale
Объект описывает аспекты системы, которые могут варьироваться от культуры к культуре, от (человеческого) языка к языку. Эти аспекты разбиты на facet
s, которые являются аргументами шаблона, которые определяют, как создаются объекты, зависящие от локализации (включая потоки ввода / вывода). Когда вы читаете из istream
или напишите ostream
фактическое написание каждого символа фильтруется через фасеты локали. Фасеты охватывают не только кодирование типов Unicode, но и такие разнообразные функции, как, например, количество записываемых больших чисел (например, с запятыми или точками), валюта, время, заглавные буквы и множество других деталей.
Однако то, что существуют средства для кодирования, не означает, что стандартная библиотека фактически обрабатывает все кодировки, и при этом не делает такой код простым для правильного выполнения. Даже такие базовые вещи, как размер символа, в который вы должны читать (не говоря уже о части кодирования), сложны, так как wchar_t
может быть слишком маленьким (искажение ваших данных) или слишком большим (тратить пространство впустую), и наиболее распространенные компиляторы (например, Visual C++ и Gnu C++) различаются по степени их реализации. Таким образом, вам обычно нужно найти внешние библиотеки для реальной кодировки.
- iconv обычно признается правильным, но примеры того, как связать его с механизмом C++, найти сложно.
- jla3ep упоминает libICU, которая очень тщательна, но API C++ не пытается играть со стандартом (насколько я могу судить: вы можете отсканировать примеры, чтобы увидеть, можете ли вы добиться большего).
Самый простой пример, который я могу найти, который охватывает все базы, взят из фасета кодека UTF-8 Boost, с примером, который специально пытается кодировать UTF-8 (UCS4) для использования потоками ввода-вывода. Это выглядит так, хотя я не предлагаю просто дословно копировать его. Требуется немного больше покопаться в источнике, чтобы понять это (и я не претендую на это):
typedef wchar_t ucs4_t;
std::locale old_locale;
std::locale utf8_locale(old_locale,new utf8_codecvt_facet<ucs4_t>);
...
std::wifstream input_file("data.utf8");
input_file.imbue(utf8_locale);
ucs4_t item = 0;
while (ifs >> item) { ... }
Чтобы больше узнать о локалях и о том, как они используют фасеты (включаяcodecvt
), взгляните на следующее:
- У Натана Майерса есть подробное объяснение языков и аспектов. Майерс был одним из разработчиков концепции локали. У него есть более формальная документация, если вы хотите пройтись по ней.
- Реализация стандартной библиотеки Apache (ранее RogueWave) имеет полный список аспектов.
- Николай Йосуттис " Стандартная библиотека C++", глава 14, посвящена этой теме.
- Стандартные англоязычные IOStreams и локали Анжелики Лангер и Клауса Крефта посвящены целой книге.
ifstream
не заботится о кодировке файла. Он просто читает символы (байты) из файла. wifstream
читает широкие байты (wchar_t
), но он до сих пор ничего не знает о кодировке файлов. wifstream
достаточно для UCS-2 - кодировка символов фиксированной длины для Unicode (каждый символ представлен двумя байтами).
Вы можете использовать библиотеку IBM ICU для работы с файлами Unicode.
International Component for Unicode (ICU) - это зрелый, переносимый набор библиотек C/C++ и Java для поддержки Unicode, интернационализации программного обеспечения (I18N) и глобализации (G11N), дающий приложениям одинаковые результаты на всех платформах.
ICU выпускается по неограниченной лицензии с открытым исходным кодом, которая подходит для использования как с коммерческим программным обеспечением, так и с другим открытым или свободным программным обеспечением.
Дизайн строки широких символов и потока широких символов предшествует UTF-8, UTF-16 и Unicode. Если вы хотите получить техническую информацию, стандартная строка и стандартный поток не обязательно работают с ASCII (просто все компьютеры используют ASCII; у вас может быть машина EBCDIC).
Рэймонд Чен однажды написал серию, иллюстрирующую, как работать с различными типами потоков и строк широких символов.