[Перевод] Почему форматы файлов Microsoft Office такие сложные?
Статья от 19 февраля 2008 года
На прошлой неделе Microsoft опубликовала спецификации форматов бинарных файлов для Office. Эти форматы выглядят безумно. Формат файла Excel 97–2003 представляет собой 349-страничный файл PDF. И это ещё не всё! В документе содержится такой комментарий:
Каждый лист [workbook] в Excel хранится в составном файле.
Видите ли, файлы Excel 97–2003 — это составные документы OLE, которые в свою очередь представляют собой некое подобие файловой системы в одном файле. Чтобы в этом разобраться, нужно прочитать 9 страниц документации. А сами спецификации больше похоже на структуры данных в С, чем на то, что мы привыкли называть спецификациями. Это иерархическая система файлов.
Если вы подумали, что почитаете эти форматы и за выходные набросаете утилитку для экспорта вордовских документов в свой блог, или создающую экселевские таблички на основе ваших персональных финансовых данных, то сложность и длина этих спецификаций должны были отбить у вас всю охоту. Нормальный программист решит, что формат бинарников из Office:
• сделан запутанным специально
• придуман каким-то страдающим от старческого маразма представителем кибернетической расы боргов
• создан безумно плохими программистами
• не может быть правильно создан или прочитан
И ошибётся. Если покопаться, то можно показать, как и почему эти форматы стали такими сложными, почему они не имеют ничего общего с плохим программированием, и что можно с этим сделать.
Первое, что нужно понять — цели у разработчиков форматов бинарников кардинально отличались от целей разработчиков, допустим, HTML.
Они должны были очень быстро работать на очень старых компьютерах. Во времена первых версий Excel для Windows 1 мегабайт памяти был не редкостью, а работать достаточно комфортно программа должна была на процессорах 80386 с частотой 20 МГц. Множество оптимизаций сделано для ускорения открытия и сохранения файлов:
• Это форматы бинарных файлов, поэтому загрузка записи обычно означает копирование последовательности байтов с диска в память, в которой появляется структура данных С. Не происходит никакого разбора или лексического анализа данных, так как это в разы медленнее простого копирования.
• Формат файлов запутан в нужных местах для ускорения типичных операций. К примеру, у Excel 95 и 97 была функция «простого сохранения», которая использовалась в качестве ускоренного варианта документа OLE, полная версия которого была не слишком быстрой для повсеместного использования. У Word было нечто подобное под названием «быстрое сохранение». Для быстрого сохранения длинных документов 14 раз из 15 все изменения просто добавлялись в конец файла, а весь файл не перезаписывался с нуля. Для жёстких дисков того времени это означало, что можно было успеть сохранить документ, допустим, за 1 секунду вместо 30. Также это означало, что удалённые части документа всё ещё хранились в файле –, а людям, как оказалось, это не было нужно.
Они были разработаны с прицелом на библиотеки. Если вам нужно было написать функцию импорта бинарника с нуля, вам нужно было поддерживать вещи вроде Windows Metafile Format (для рисования) и OLE Compound Storage. При работе под Windows для них есть библиотеки, поэтому поддержка таких функций была тривиальным делом. Но если писать всё с нуля, всё пришлось бы делать самому.
У Office была поддержка составных документов, к примеру, можно было включить электронную таблицу в файл Word. Идеальный парсер Word должен был суметь сделать что-то умное с включённой таблицей.
Они не разрабатывались для использования в других приложениях. Довольно разумное на тот момент предположение заключалось в том, что формат Word будет писать и читать только программа Word. Поэтому когда программист из команды разработчиков Word принимал решение о смене формата файла, его волновали лишь а) скорость работы и б) минимальное количество строк в коде Word. Идеи вещей типа SGML и HTML, заменяемых, открытых и стандартизированных форматов, не были популярными, пока интернет не сделал такие вещи практичными. Этот момент пришёл через 10 лет после разработки форматов файлов Office. Всегда предполагалось использование программ для экспорта и импорта. У Word есть поддержка формата для простого обмена документами по имени RTF, существовавшего почти с самого начала.
Им нужно было отразить всю сложность приложений. Каждую галочку, каждую возможность форматирования и каждую функцию Microsoft Office необходимо было хранить в файлах. Поэтому для создания идеального клона Word, читающего его файлы, нужно было реализовать все его функции. Если вы создаёте программу для работы с текстом — конкурента Word, которая должна уметь загружать его файлы, у вас может занять немного времени сама загрузка указанных в файле опций. Но реальное отображение их всех на странице — это задача более сложная. А если её не решить, то ваши клиенты откроют вордовский файл в вашем клоне, и всё форматирование может поломаться.
Им нужно было отражать историю развития программ. Множество сложных вещей в форматах — это старые, сложные, ненужные и редко используемые функции. Они присутствуют там лишь для обратной совместимости и потому, что для разработчиков ничего не стоит оставить код в покое. Но чтобы тщательно выполнить работу разборки или записи этих файлов, вам придётся повторить всю эту работу, что была проделана в Microsoft за 15 лет. В текущие версии Word и Excel вложены тысячи человеко-часов работы, и для клонирования этих программ вам придётся вложить свои тысячи человеко-часов. Формат файла — это просто краткое обобщение всех поддерживаемых приложением функций.
Просто для примера разберём одну возможность подробнее. Лист Excel — это набор разных записей BIFF. Рассмотрим самую первую запись в спецификации — это запись под именем 1904.
В спецификации об этой записи написано весьма туманно. Просто написано, что «запись 1904 показывает, используется ли система дат 1904». Классический пример бесполезной спецификации. Если бы вы были разработчиком, и наткнулись бы на такое «объяснение», вы бы весьма оправданно пришли к заключению, что Microsoft что-то скрывает. Такое описание недостаточно само по себе, вам нужно искать дополнительную информацию. Я поясню: существует два типа листов Excel. В одних даты начинаются с 1/1/1900 (в них же ошибка високосного года специально создана для совместимости с форматом 1–2–3), в других — с 1/1/1904. Excel поддерживает оба варианта — поскольку первая его версия, для Mac, использовала второй вариант, который был системным, а Excel для Windows должен был иметь возможность импортировать файлы 1–2–3, использовавшие даты с 1/1/1900. Уже на этом месте можно расплакаться.
Оба типа файлов, 1900 и 1904, встречаются в изобилии в дикой природе, в зависимости от того, пришли они с Mac или Windows. Автоматическая конвертация дат может привести к ошибкам, поэтому Excel сам тип файла не меняет. Для разборки файлов Excel приходится работать с обоими. А это значит, что вам не просто нужно загрузить этот бит из файла, но ещё и переписать весь код разбора и показа дат, чтобы обрабатывать оба варианта. Это работа на несколько дней.
Работая над клоном Excel вы встретите множество таких скрытых деталей по работе с датами. Когда Excel преобразовывает числа в даты? Как работает форматирование? Почему 1/31 интерпретируется как 31 января текущего года, а 1/50 — как первое января 1950? Все эти детали нельзя описать без того, чтобы получившееся описание не сравнялось по объёму с исходниками Excel.
И это только одна из сотен BIFF-записей, и одна из простейших. Большинство из них настолько сложные, что могут заставить взрослого программиста рыдать.
Единственное возможное решение будет следующим. Конечно, Microsoft оказала большую услугу, опубликовав форматы файлов, но импортировать их или сохранять в них от этого легче не будет. Это безумно сложные приложения, и вы не можете просто реализовать 20% самых популярных функций и рассчитывать, что 80% остальных людей будут счастливы. Спецификации бинарников в лучшем случае сохранят вам пару минут при реверс-инжиниринге сложной системы.
Но я обещал рассказать, что с этим делать. Почти всем популярным приложениям не нужно заниматься чтением и записью бинарников от Office. Есть две альтернативы: дать Office работать самому, или использовать более простые форматы файлов.
Пусть Office работает сам. У Word и Excel есть весьма полные модели объектов, доступные через COM Automation, благодаря чему в программе можно сделать всё. Во многих случаях лучше повторно использовать код из Office вместо попыток написать его заново. Примеры:
- У вас есть веб-приложение, которому нужно вывести файлы Word в формате PDF. Я бы сделал это так: несколько строк на Word VBA загружают файл и сохраняют его в PDF через встроенный в Word 2007 механизм. Этот код можно вызывать напрямую, даже из ASP или ASP.NET, работающего под IIS. Первый запуск Word займёт несколько секунд. В последствии Word будет находиться в памяти под управлением COM-системы. Для обычных веб-приложений такая система работает довольно быстро.
- Та же задача под Linux. Купите один сервер Windows 2003, установите на него лицензионный Word, и настройте простой веб-сервис. Работы на полдня, с применением C# и ASP.NET
- Та же задача, но с возможностью масштабирования. Настройте балансировку нагрузки перед любым необходимым количеством коробок из второго шага. Никакого программирования не потребуется.
Такой подход сработает со всеми распространёнными задачами, связанными с Office. К примеру:
• Открытие листа Excel, сохранение некоторых данных в ячейках, подсчёт и выдача результата.
• Использования Excel для создания графиков в формате GIF
• Вытаскивание любой информации из файла Excel без разбора форматов файлов
• Преобразование файла Excel в CSV (другой подход — использовать драйверы Excel ODBC и забирать данные через SQL-запросы)
• Редактирование документов Word
• Заполнение форм в Word
• Преобразование файлов между разными форматами, которые поддерживает Office (существуют возможности импортирования десятков форматов текстовых процессоров и электронных таблиц).
Во всех этих случаях есть возможность объяснить объектам Office, что они работают не в интерактивном режиме, так что им не надо обновлять экран и запрашивать ввод пользователя. На этом пути есть несколько подводных камней, и он официально не поддерживается Microsoft, так что перед началом работы прочтите соответствующий материал.
Используйте форматы попроще. Если вам просто нужно программно создать документы для Office, почти всегда есть формат получше, который затем можно свободно открыть в Word или Excel.
• Для создания табличных данных и использования их в Excel используйте CSV.
• Для поддержки вычислений, которые не умеет делать CSV, возьмите формат WK1, доставшийся от Lotus 1–2–3. Он гораздо проще, чем у Excel, и открывается им на раз.
• Если вам ну очень надо создавать нативные файлы Excel, возьмите очень старую его версию. 3.0 — хороший выбор, там не было составных документов. Сохраните в Excel 3.0 минимальный файл только с теми функциями, которые вам необходимы, и используйте его как пример минимальной BIFF-записи.
• Для документов Word используйте HTML
• Если вам очень надо создать файл для Word с модным форматированием, проще всего создать RTF. Всё, что умеет Word, можно написать в RTF, но этот формат текстовый, так что в нём что-то можно поменять руками и он будет работать. Вы можете создать красиво отформатированный файл в Word, сохранить в RTF и использовать простую замену текста.
В общем, если вы не пытаетесь создать конкурента для Office, который может читать и писать все файлы из Office (для чего вам потребуются тысячи часов работы), то попытки чтения или записи в его бинарные файлы окажутся самым затратным способом для любой задачи, которая у вас есть.