Летом я написал класс для чтения файлов двоичного формата. Для максимальной переносимости использовалась исключительно стандартная библиотека. Напомню, что вся работа с двоичными файлами в C++ должна проводиться при помощи классов-потоков вроде fstream. Объект класс fstream инициализируется конструктором вида(как и все классы этой группы):
fstream (const char *s, int)
Здесь const char* - C-строка, где располагается адрес файла, второй аргумент - флаги, определяющие режим доступа к файлу. Это - именно определенная стандартом конструкция и, полагаю, очень часто используется в различных библиотеках.
Напомню также, что в NTFS для записи путей к файлам используется Unicode (UTF-16). UTF-16 для хранения информации о символе использует два байта и не совместима со стандартной ASCII.
В этот самый const char* никак не записать путь, состоящий из символов UTF-16, адрес надо указывать именно в однобайтных символах.
Забавно получается! Стандартная библиотека языка поддерживает чтение многобайтных кодировок из файла, но не гарантирует открытие названий файлов многобайтных кодировок вроде UTF-16 в NTFS; и открываемый под Windows адрес обязательно должен состоять из символов ASCII.
Пары байт Unicode пройти как последовательность символов в памяти не могут, потому что в них могут встретиться нулевые с точки зрения C-строк последовательности, закрывающие строку.
UTF-8 же можно передавать в таких строках. Дело в том, что последняя варьирует число используемых байт от одного до четырех, сохраняя при этом обратную совместимость с 7-битной таблицей символов ASCII; гарантируется, что ни один из байтов не будет представлять собой закрывающий C-строку нулевой байт.
Получилось, что файлы с русскими символами в пути под Линуксом открывались, а под Виндой - нет, хотя я использовал средства из стандартной библиотеки.
Для совместимости пришлось переделывать мой класс под использование файловых дескрипторов C, одинаково работающих и в современных Линуксах, и в Видоусах.
4 комментария:
Это ж надо, а!
:-) Чем дышу, о том и пишу!
Мне понравилось. Вова, только я кое что не понял: ты добавил конвертацию UTF16->UTF8? Или класс string использовал?
Заур, да там дело в том, что fstream по стандарту инициализировать можно только C-строкой, то есть const char*. В разных компиляторах могут встретиться разные расширения класса fstream, но для настоящей переносимости надо пользоваться чем-нибудь универсальным и стандартным.
Вообще мне надо было файл, уже открытый в специальном и универсальном классе QT - QFile, открыть моим классом. QFile может вернуть как адрес файла в практически любой нужной кодировке, так и просто file descriptor(тот, что в стандарте C описан).
Пришлось немного изменить используемой в моем старом классе стандартный fstream так, чтобы кушал он при создании этот самый file descriptor.
Плохо то, что это изменение - не стандарт, и реализуемо только для компиляции в GCC.
Отправить комментарий