Тип файла
Легко понять, что структурированные файлы предоставляют системе и программисту
информацию о структуре хранящихся данных, но не дают никаких сведений
о форме представления и смысле этих данных.
Например, с точки зрения системы исходный текст программы на языке С
и документ в формате LATEX совершенно идентичны: и то, и другое представляет
собой текстовый файл (или, если угодно, файл с записями переменной длины).
Однако, если мы попытаемся подать наш документ на вход С-компилятора,
мы получим множество синтаксических ошибок и никакого Полезного результата.
Этот пример показывает, что во многих случаях желательно связать с файлом
— неважно, структурированный ли это файл или байтовый поток — какую-то
метаинформацию: в каком формате хранятся данные, какие операции над ними
допустимы, а иногда и сведения о том, кому и зачем эти данные нужны.
По-видимому, наиболее общим решением этой проблемы был бы объектно-ориентированный
подход, в котором файл данных рассматривается как объект, а допустимые
операции — как методы этого объекта. Ни в одной из известных автору ОС
эта идея в полной мере не реализована, но пользовательские интерфейсы
многих современных ОС предоставляют возможность ассоциировать определенные
действия с файлами различных типов.
Так, например Explorer — пользовательская оболочка Windows 95 и Windows
NT 4.0 — позволяет связать ту или иную программу с файлами, имеющими определенное
расширение, например, программу MS Word с файлами имеющими расширение
DOC. Когда пользователь нажимает левую кнопку мыши на значке, представляющем
такой файл, то автоматически запускается MS Word. Эти же ассоциации доступны
и из командной строки — можно напечатать start Доклад. DOC, и опять-таки
запустится MS Word.
Такое связывание очень просто в реализации и сделано не только в Explorer,
но и в простых текстовых оболочках вроде Norton Commander. От ОС при этом
требуется только дать возможность каким-то образом различать типы файлов.
Первые попытки ассоциировать с файлом признак типа были сделаны еще в
60-е годы. При этом идентификатор типа добавлялся к имени файла в виде
короткой, но мнемонической последовательности символов — расширения (extension).
В большинстве современных ОС расширение отделяется от имени символом ".",
но проследить истоки этой традиции автору не удалось. При этом, например,
файлы на языке С будут иметь расширение "с", на
C++ — "С", а документы в формате LATEX — "tex".
В ОС семейства Unix имя файла может содержать несколько символов ".",
и, таким образом, файл может иметь несколько каскадированных расширений.
Например, файл "main.С" — это программа на языке C++; "main.C.gz"
— это программа на языке C++, упакованная архиватором GNU Zip с целью
сэкономить место; "main.C.gz.crypt" — это программа, которую
упаковали и потом зашифровали, чтобы никто посторонний не смог ее прочитать;
наконец, "main.C.gz.crypt.uue" — это упакованная и зашифрованная
программа, преобразованная в последовательность печатаемых символов кода
ASCII, например, для пересылки по электронной почте.
В принципе, расширения являются вполне приемлемым и во многих отношениях
даже очень удобным способом идентификации типа файла. Одно из удобств
состоит в том, что для использования этого метода не нужно никаких или
почти никаких усилий со стороны ОС: просто программы договариваются интерпретировать
имя файла определенным образом.
Пример 11.1. Командная строка компилятора
ее main.С c-code.c asm-code.s obj-code.o\ libraryl.a Iibrary2.so
-o program
Например, стандартный драйвер компилятора в системах семейства Unix
— программа со — определяет тип файла именно по расширению. Командная
строка, приведенная в примере 11.1, будет интерпретироваться следующим
образом.
- main.С — текст на языке C++. Его нужно обработать препроцессором
и откомпилировать компилятором C++, а затем передать то, что получится,
редактору связей. Большинство компиляторов в Unix генерируют код на
ассемблере, т. е. вывод компилятора еще нужно пропустить через ассемблер.
- c-code.c — текст на языке С. Он обрабатывается так
же, как и программа на С ++, только вместо компилятора C++ используется
компилятор С.
- asm-code.s — программа на языке ассемблера. Ее нужно
обработать ассемблером и получить объектный модуль.
- obj-code.o — объектный модуль, который непосредственно
можно передавать редактору связей.
- library1.a — объектная библиотека, которую нужно использовать
для разрешения внешних ссылок наравне со стандартными библиотеками.
- library2.so — разделяемая библиотека, которую надо
связать с создаваемым динамическим модулем.
Многие ОС, разработанные в 70-е годы, такие как RT-11, RSX-11, VAX/VMS,
CP/M, навязывают программисту разделение имени на собственно имя и расширение,
интерпретируя точку в имени файла как знак препинания. В таких системах
имя может содержать только одну точку и соответственно иметь только одно
расширение. Напротив, в ОС нового поколения — OS/2, Windows NT и даже
в Windows 95 — реализована поддержка имен файлов свободного формата, которые
могут иметь несколько каскадированных расширений, как и в Unix.
Однако никакие средства операционной системы не могут навязать прикладным
программам правил выбора расширения для файлов данных. Это приводит к
неприятным коллизиям. Например, почти все текстовые процессоры от Лексикона
до Word 2000 включительно используют расширение Файла .doc (сокращение
от document), хотя форматы файлов у различных процессоров и даже у разных
версий одного процессора сильно различаются.
Другая проблема связана с исполняемыми загрузочными модулями. Обычно система
использует определенное расширение для исполняемых файлов.
Так, VMS и системы семейства СР/М используют расширение .ехе: сокращение
от executable (исполняемый). Однако по мере развития системы формат загрузочного
модуля может изменяться. Так, например, OS/2 v3.0 поддерживает по крайней
мере шесть различных форматов загрузочных модулей.
- 16-разрядные сегментированные загрузочные модули: формат
OS/2 х
- 32-разрядные загрузочные модули, использующие "плоскую"
(flat) модец, памяти: формат OS/2 2.x (LE — Linear Executable).
- 32-разрядные модули нового формата, использующие упаковку
кода данных: формат OS/2 3.x (LX — Linear executable extended).
- ехе- и corn-модули DOS.
- Загрузочные модули Win 16 (NE).
- Загрузочные модули Win32s (РЕ — Portable Executable).
Для исполнения последних трех типов программ OS/2 создает виртуальную
машину, работающую в режиме совместимости с 8086. Эта задача запускает
копию ядра DOS и, если это необходимо, копию MS Windows, которые уже выполняют
загрузку программы. Загрузочные модули всех трех "родных" форматов
загружаются системой непосредственно. Так или иначе, загрузчик должен
уметь правильно распознавать все форматы. При этом он не может использовать
расширение файла: файлы всех перечисленных форматов имеют одинаковое расширение
ЕХЕ.
Похожая ситуация имеет место в системах семейства Unix, где бинарные загрузочные
модули и командные файлы вообще не имеют расширения. При этом большинство
современных версий системы также поддерживает несколько различных исторически
сложившихся форматов загрузочного модуля.
Разработчики Unix столкнулись с этой проблемой еще в 70-е годы. В качестве
решения они предложили использовать магические числа
(magic number) или сигнатуры (signature—
подпись) — соглашение о том, что файлы определенного формата содержат
в начале определенный байт или последовательность байтов. Первоначально
это были численные коды; файл /etc/magic содержал коды, соответствующие
известным типам файлов. Позднее в качестве магических чисел стали использоваться
длинные текстовые строки. Так, например, изображения в формате CompuServe
GIF 87а должны начинаться с символов GIF87a.
Легко понять, что магические числа ничуть не лучше расширении, а во многих
отношениях даже хуже. Например, пользователь, просмотрев содержимое каталога,
не может сразу узнать типы содержащихся в нем файлов. Еще хуже ситуация,
когда расширение файла не соответствует его реальному типу. Это будет
вводить в заблуждение не только пользователя, но и некоторые программы,
полагающиеся при определении формата на расширение вместо магического
числа.
С длинными мнемоническими текстовыми строками связана еще одна забавная
проблема, которая может иметь неприятные последствия. Например-текстовый
файл следующего содержания:
GIF87a — это очень плохой формат хранения изображений. Он будет воспринят
некоторыми программами как изображение в формате CompuServe (GIF 87а,
каковым он, безусловно, не является.
Оригинальное развитие идея магических чисел получила в современных системах
семейства Unix, где сигнатура вида #!/bin/sh означает, что данный файл
представляет собой интерпретируемую программу, интерпретатор которой хранится
в файле /bin/sh (в данном случае это стандартный командный процессор).
Пытаясь как-то решить проблему идентификации типа файла, разработчики
Macintoch отказались как от расширений, так и от магических чисел. В MacOS
каждый файл состоит из двух частей или ветвей (forks):
ветви данных (data fork) и ветви ресурсов
(resource fork). Кроме идентификатора типа файла, ветвь ресурсов
хранит информацию о:
- значке, связанном с этим файлом;
- расположении значка в открытой папке (folder);
- программе, которую нужно запустить при "открытии"
этого файла.
Еще дальше в этом же направлении пошли разработчики системы OS/2. В
этой системе с каждым файлом связан набор расширенных
атрибутов (extended attributes). Атрибуты имеют вид "ИМЯ:Значение".
При этом значение может быть как текстовой строкой, так и блоком двоичных
данных произвольного формата и размера. Некоторые расширенные атрибуты
используются оболочкой Workplace Shell (WPS) как эквивалент ветви ресурсов
в MacOS: для идентификации типа файла, связанного с ним значка и размещения
этого значка в открытом окне. Тип файла идентифицируется текстовой строкой.
Например, программа на языке С идентифицируется строкой
С code. Это резко уменьшает вероятность конфликта имен типов —
ситуацию, довольно часто возникающую при использовании расширений или
магических чисел.
Другие атрибуты могут применяться для других целей. Например, LAN Server
— файловый сервер фирмы IBM — использует расширенные атрибуты для хранения
информации о владельце файла и правах доступа к нему. Некоторые текстовые
редакторы применяют расширенные атрибуты для хранения положения курсора
при завершении последней сессии редактирования, так что пользователь всегда
попадает в то место, где он остановился в прошлый раз.
Кроме того, расширенные атрибуты могут использоваться и для хранения сведений
о назначении файла. В OS/2 существуют предопределенные расширенные атрибуты
с именами subject (тема), comment
(комментарии) и Key phrases (ключевые фразы),
которые могут, например, использоваться для поиска документов, относящихся
к заданной теме. К сожалению, такой поиск возможен, только если создатель
документа позаботился о присвое нии этим атрибутам правильных значений. |