Россия, Звенигород |
Объекты XPCOM
16.2.5. Файлы и папки
В этом разделе рассказано, каким образом можно находить файлы и папки на том компьютере, где установлена платформа Mozilla. Здесь мы используем термин папка, а не каталог, поскольку последний в контексте данной лекции относится, прежде всего, к службам каталогов (directory services).
Работа с файлами в Mozilla довольно сложна в силу ограничений, связанных с требованиями переносимости и соответствия стандартам WWW. Код, работающий с объектами XPCOM, представляющими файлы, должен быть переносим между платформами (как минимум, между UNIX, Microsoft Windows и Macintosh), а понятие файла или папки должно быть совместимо с понятием URL.
Требования переносимости влияют на работу с именами файлов и папок. Платформа Mozilla не поддерживает концепцию полного пути к файлу, выраженного в виде строки, поскольку синтаксис пути для различных платформ отличается; на некоторых платформах отсутствует само понятие пути. Даже непосредственная работа с именем файла, не содержащим полного пути, может привести к проблемам. Поэтому платформа Mozilla стремится посредством специальных абстракций изолировать разработчика приложений от непосредственных манипуляций с путями и именами файлов, за исключением тех случаев, когда требование переносимости несущественно.
Ключевой абстракцией, предназначенной для решения этой проблемы, является интерфейс nsIFile. Объекты, поддерживающие этот интерфейс, часто используются в скриптах, но разработчики редко создают их вручную или извлекают информацию о пути и имени файла, хранящуюся внутри такого объекта. Это означает, что такие объекты редко создаются при помощи стандартной пары XPCOM:
@mozilla.org/file/local;1 nsIFile
Вместо этого объекты с интерфейсом nsIFile создаются непрямым образом, при помощи методов других интерфейсов. Для локальных файлов существует специализированный вариант интерфейса nsIFile, которому соответствует следующая пара:
@mozilla.org/file/local;1 nsILocalFile
Оба интерфейса могут представлять как файлы, так и папки. В существующем коде можно встретить и устаревший интерфейс для работы с файлами, который в настоящее время не рекомендован к использованию:
@mozilla.org/filespec;1 nsIFileSpec
Таким образом, разработчик приложения полагается на то, что объект, представляющий файл, будет создан, инициализирован и возвращен методом другого интерфейса. Существует целый ряд способов получения объектов nsIFile, представляющих нужные файлы:
- Служба каталогов может на основе переданных ей псевдонимов возвращать объекты, представляющие известные файлы или папки.
- Пользователю может быть предложено выбрать файл или папку. Объект, создавший диалоговое окно для пользователя, затем возвращает готовый объект, соответствующий выбранному файлу или папке.
- Файл или папка могут быть получены путем обработки URL. Этот способ далеко не всегда работает автоматически, здесь существенны как контекст URL, так и контекст файла.
- Объект, представляющий файл или папку, может быть получен на основе объекта, представляющего другой файл или папку, если те доступны. Чтобы получить родительский каталог для данного файла, достаточно воспользоваться свойством parent интерфейса nsIFile. Для получения содержимого папки может использоваться свойство directoryEntries того же интерфейса.
- Если приложение не является переносимым, можно построить строку JavaScript, содержащую абсолютный или относительный путь в формате UNIX или Microsoft Windows, а затем инициализировать объект nsIFile при помощи этой строки.
- Наконец, если объект nsIFile был использован при создании потока, канала или другого объекта XPCOM, как правило, его можно получить в дальнейшем, используя методы этого другого объекта.
Примеры использования таких методов приведены ниже в этом разделе.
Интерфейс nsIFile позволяет решить проблему переносимости операций с файлами, однако остается вопрос интеграции файлов и URL. Для работы с URL используются объекты с интерфейсом nsIURL, использование которых описано в разделе "Web-скрипты". Для взаимного преобразования файлов и URL используется следующая пара XPCOM:
@mozilla.org/network/protocol;1?name=file nsIFileProtocolHandler
Этот интерфейс поддерживает методы newFileURI() и getFileFromURLSpec(), которые и выполняют необходимые преобразования. Интерфейс nsIIOService также поддерживает метод newFileURI().
Интерфейсы nsIFile и nsIURL позволяют получать строки, представляющие фрагменты пути к файлу или URL. Выполнив определенные операции над этими строками, приложение может создать объект nsIURL, соответствующий объекту nsIFile, и наоборот.
16.2.5.1. Использование каталога файловой системы
Каталог файловой системы подробно описан в разделе "Конфигурация платформы", там же приведен и ряд примеров. Здесь мы приведем короткий пример, демонстрирующий поиск папки, используемой для создания временных файлов (см. листинг 16.1).
var Cc = Components.classes; var Ci = Components.interfaces; var dp = Cc["@mozilla.org/file/directory_service;1"]; dp = dp.createInstance(Ci.nsIDirectoryServiceProvider); var folder = dp.getFile("TmpD", {});Листинг 16.1. Инициализация объекта nsILocalFile при помощи каталога файловой системы.
Центральным элементом данного кода является использование специального псевдонима TmpD для папки временных файлов. Такой подход пригоден для поиска файлов и каталогов, которые имеют определенное значение для платформы Mozilla, и для которых определены псевдонимы. Таблицы существующих псевдонимов приведены ниже, в разделе "Каталог файловой системы".
16.2.5.2. Выбор файла пользователем
Создание диалогового окна для выбора файла пользователем с последующим созданием объекта nsILocalFile на основе выбранного файла показано в листинге 16.2.
var file; var CcFP = Components.classes["@mozilla.org/filepicker;1"]; var CiFP = Components.interfaces.nsIFilePicker; var fp = CcFP.createInstance(CiFP); // используйте любые допустимые параметры для инициализации объекта nsIFilePicker fp.init(window, "File to Read", Picker.modeOpen); if ( fp.show() != fp.returnCancel ) file = fp.file;Листинг 16.2. Создание объекта nsILocalFile на основе выбора пользователя.
Как видно из приведенного кода, объект nsIFilePicker создает объект nsILocalFile, который можно получить, используя свойство file.
Если полученный объект соответствует папке, его можно преобразовать к другой папке или файлу при помощи строки, представляющей относительный путь к ним от исходного каталога. Для этого используется метод appendRelativePath(), который принимает в качестве аргумента относительные пути, не содержащие подстроки "..".
Приняв определенные меры предосторожности, можно построить сроку относительного пути, не теряя переносимости. К счастью, все системы семейства Microsoft Windows, UNIX и Macintosh поддерживают прямой слеш (/) в качестве разделителя элементов пути (хотя окно Microsoft Windows для работы с командной строкой DOS не поддерживает ее). Имейте в виду, что некоторые пользователи Microsoft Windows (и, в отдельных случаях, пользователи Linux) могут не иметь поддержки длинных имен файлов (LFN), что ограничивает имена файлов форматом "8.3" или 14 символами. Интерфейс nsIFile поддерживает ряд атрибутов и методов, которые могут быть полезны при формировании переносимого пути.
Наконец, если приложение не должно быть переносимым или допускает использование отдельных фрагментов кода для каждой из поддерживаемых платформ, можно инициализировать nsILocalFile непосредственно при помощи строки, представляющей путь, использовав для этого метод initWinPath(). При этом следует экранировать символы обратного слеша в путях Microsoft Windows (\\) или использовать вместо них прямой слеш. Отдельный код для различных платформ может иметь вид ряда операторов if, проверяющих текущую платформу.
16.2.5.3. Использование строкового литерала или URL
Как уже было сказано, если приложение не должно быть переносимым или допускает использование отдельных фрагментов кода для каждой из поддерживаемых платформ, объект nsILocalFile может быть инициализирован непосредственно при помощи строки. Пример соответствующего кода приведен в листинге 16.3.
var file; var CcLF = Components.classes["@mozilla.org/local/file;1"]; var CiLF = Components.interfaces.nsILocalFile; var file = CcLF.createInstance(CiLF); file.initWithPath("C:\\WINDOWS\NOTEPAD.EXE");Листинг 16.3. Инициализация объекта nsILocalFile при помощи литерала.
Литерал "C:" можно заменить переносимым объектом, представляющим корневую папку файловой системы, которую можно получить при помощи каталога файловой системы и псевдонима DrvD. Использование в качестве разделителя прямого слеша (который поддерживают все платформы, включая Microsoft Windows) также сделает этот фрагмент более переносимым.
Локальный файл может быть также задан с помощью URL. Преобразовать URL в файловый объект можно следующим образом:
var conv = Cc["@mozilla.org/network/protocol;1?name=file"]; conv = conv.createInstance(Ci.nsIFileProtocolHandler); var url = ... // Существующий объект nsIURL var file = conv.getFileFromURLSpec(url);
URL, используемый в этом примере, должен иметь префикс file:. Путь к файлу можно также получить, используя свойство filePath объекта nsIURL, например:
file.initWithPath(myURL.filePath.replace(/\|/,":"));
В данном случае объект myURL поддерживает интерфейс nsIURL. Замена регулярного выражения при помощи метода replace() приводит фрагмент URL вида "C|/test" к "C:/test". Нужно иметь в виду, что сетевые пути в системе Microsoft Windows (пути UNC) вида \\saturn\tmp при представлении в виде URL требуют префикса из пяти прямых слешей (http://///saturn/tmp), причем соответствующее соглашение еще не устоялось окончательно.
16.2.5.4. Работа с файлами и папками
После того как файл найден и представлен соответствующим объектом, его читают, в него записывают данные или выполняют с ним другие действия.
В программном окружении JavaScript платформы Mozilla не используются дескрипторы или идентификаторы (handle) файлов, а также указатели на файлы. Это означает, что в JavaScript не могут быть созданы каналы (pipes), основанные на дескрипторах файлов. Интерфейс nsIPipe создает канал уровня приложения, который не является традиционным каналом UNIX. Из скриптов невозможно создавать именованные каналы (или символические ссылки), однако можно использовать для чтения и записи уже существующие каналы. Говоря коротко, платформа Mozilla не предназначена для прямого доступа к файлам на низком уровне из скриптов JavaScript.
Вместо идентификаторов файлов Mozilla использует объекты. При этом скрипту приходится работать, как минимум, с двумя объектами. Один из них представляет используемый файл или папку – это может быть объект nsIFile или nsILocalFile. Этот объект – спецификатор имени файла. Второй объект представляет поток данных, из которого данные читаются и в который они пишутся. Это спецификатор содержимого файла. Для работы с файлом должны быть созданы оба объекта, причем как связанные друг с другом. Потоки и другие средства работы с содержимым подробно обсуждаются ниже в разделе "Передача данных". Потоки, доступные из JavaScript на платформе Mozilla, аналогичны потокам C++ или Java, однако в данном случае перегрузка операторов отсутствует.
16.2.5.5. Работа с архивами ZIP и JAR
Следующая пара XPCOM, основанная на тех же принципах, что и nsIFile, обеспечивает доступ к содержимому локальных файлов .zip и .jar:
@mozilla.org/libjar/zip-reader;1 nsIZipReader
С помощью этого интерфейса могут также создаваться новые архивы Zip.
Конверторы потоков, описанные в разделе "Преобразование содержимого потоков", могут использоваться для работы с потоком сжатого содержимого в необработанном виде.