Почему форматы Microsoft Office такие сложные? (И как это обойти)

From The Joel on Software Translation Project

Jump to: navigation, search

Автор: Джоэл Спольски
Переводчик: Михаил Меркурьев
В оригинале статья называлась Why are the Microsoft Office file formats so complicated? (And some workarounds) и была написана 19 февраля 2008


На прошлой неделе Microsoft опубликовал форматы двоичных файлов Office. Формат Excel 97–2003 занимает в PDF 349 страниц. Постойте, она не совсем полная! В документе есть интересный комментарий:

Каждая книга Excel хранится в составном файле [один из форматов OLE — прим. перев.].

Итак, файлы Excel 97–2003 — составные документы OLE, которые, по сути, являются файловой системой внутри одного большого файла. Эта система достаточно сложна, чтобы вам пришлось-таки прочитать ещё одну 9-страничную спецификацию. Все эти «спецификации» больше похожи на структуры данных Си, а не на спецификацию в привычном нам смысле. Это целая многоуровневая файловая система.

Если вы решили прочитать эту документацию в надежде за выходные написать импорт документов Word для вашего блог-движка, или вывести ваши личные финансы в виде таблицы Excel — сложность и длина спецификации быстро отобьют у вас эту охоту. Нормальный программист придёт к выводу, что двоичные форматы Office 1) намеренно сделаны сложными и тёмными; 2) такое мог выдумать только сумасшедший киборг; 3) были созданы крайне неумелыми программистами; и 4) невозможно корректно считать и записать.

Смею вас заверить: всё это неверно. Подумаем вместе, и я вам покажу, почему эти форматы стали такими сложными, почему это не говорит о непрофессионализме Microsoft и как обойти всё это.

Они рассчитаны на очень слабые компьютеры. В первых версиях Excel для Windows, 1 мегабайт ОЗУ был обычным объёмом памяти, и 80386 с 20 мегагерцами мог с комфортом гонять Excel. В форматах Microsoft было много оптимизации, которая позволяла быстрее открывать и сохранять файлы.

  • Это двоичные форматы, так что загрузка набора полей данных — это просто запись нескольких байтов с диска в память, а в памяти — те самые структуры Си. Никакого лексического и синтаксического разбора, которые в разы медленнее простого считывания.
  • Формат подстроен так, чтобы важнейшие операции выполнялись быстро. Например, в Excel 95 и 97 есть режим Simple Save, который применяется вместо составного документа OLE в тех случаях, когда последний недостаточно быстр. В Word’е есть «быстрое сохранение» : чтобы быстро записать длинный документ, 14 раз из 15, вместо того, чтобы писать весь файл с нуля, изменения дописываются в конец файла. На тогдашних винчестерах это означало, что файл сохраняется всего секунду, а не тридцать. Оборотной стороной быстрого сохранения стало то, что удалённая тайная информация остаётся в файле — поэтому в Office 2003 от быстрого сохранения отказались.

Они были рассчитаны на широкое использование библиотек. Если вы хотите написать с нуля двоичный импортёр, вам требуется поддерживать такие вещи, как Windows Metafile (для векторных рисунков), составные контейнеры OLE и т. д. Если вы на Windows, всё это тривиально — оно есть в Windows API. Но если вы пишете всё с полнейшего нуля, всё это приходится реализовывать. В Office реализована широкая поддержка составных документов: например, в Word можно вставить таблицу Excel. Настоящий импортёр Word должен сделать что-то умное с внедрённой через OLE таблицей.

Ни о каком взаимообмене не было и речи. Вполне разумное для своего времени предположение: формат должен читаться и записываться только Word’ом. Это значит, что если программисту, который работает над Word’ом, потребовалось менять формат, он должен думать только над двумя вещами: а) формат должен быть быстродействующим; и б) что занимает меньше строк с учётом всех наработок Word’а. Такие идеи, как SGML и HTML — стандартизованные, пригодные для обмена данными форматы — появились лишь тогда, когда Интернет поставил во главу угла обмен документами; двоичные форматы Office разрабатывались за десятилетие до этого. Предполагалось, что если нужен обмен — всегда можно написать импортёр или экспортёр. В действительности, в Word есть формат, пригодный для обмена — RTF, который был там практически с самого начала. RTF полностью поддерживается и сейчас.

Они должны отражать всю сложность Office. Каждая галочка в диалогах, каждое свойство форматирования — всё это должно записываться где-то в файле. В меню «Абзац» есть пункт «Не отрывать от следующего», который переносит абзац на новую страницу так, чтобы он был на одной странице со следующим? Это тоже часть формата. А это значит, что если вам нужно написать точный клон Word’а, который способен корректно читать документы Word’а, вы должны реализовать эту функцию. Если вы создаёте соперника Word’а, который будет загружать его документы, вам потребуется всего минута, чтобы считать этот бит из файла. Но чтобы переделать алгоритм разбиения на страницы так, чтобы он работал с этим битом, нужны недели. Но это нужно: иначе пользователи откроют свои файлы Word’а и увидят «поплывшие» страницы.

Они должны отражать всю историю Office. Многие особенности формата связаны с функциями, которые очень стары, сложны и редко используются. Они всё ещё остались ради обратной совместимости — ведь Microsoft ничего не стоит оставить старый код. Но если вы хотите разбирать и писать эти файлы, вам придётся пройти весь тот путь, который прошли безвестные программисты из Microsoft 15 лет назад. В текущие версии Word’а и Excel’я вложены уже тысячи человеко-лет — и если вы хотите сделать их клон, вам придётся работать тысячи лет. Формат файла — это всего лишь краткое описание того, что программа делает.

Для примера рассмотрим подробно один маленький пример. Файл Excel — это куча записей в формате BIFF. Самая первая запись в этом файле называется 1904.

Спецификация Excel по поводу этой записи крайне немногословна: запись 1904 задаёт, «используется ли система дат с 1904 года». Ой, классический пример бесполезной спецификации. Если бы вы были разработчиком, работающим с форматом Excel’я, вы бы подумали, что Microsoft что-то скрывает. Действительно, чтобы понять это предложение, требуется дополнительная информация, которую я и хочу поведать. Есть два вида файлов Excel: с датами, начинающимися с 1 января 1900 года (вместе с ошибкой, которая считает 1900 год високосным и намеренно оставлена для совместимости с Lotus 1–2–3), и с датами, начинающимися с 1 января 1904 года. Excel поддерживает обе системы: в первой версии для Mac использовалась нумерация с 1904 года, а Excel для Windows должен был импортировать файлы 1–2–3 с нумерацией с 1.01.1900. Думаю, этого хватает, чтобы бросить вас в слёзы. Неважно, в какой точке истории программист сделал глупость — но вот она перед вами.

Широко распространены файлы и с нумерацией 1900, и с нумерацией 1904 — обычно в зависимости от того, создавался он на Windows или на Mac’е. Конвертация из одного формата в другой может привести к ошибкам целостности данных, так что Excel автоматически не меняет типа файлов. И это не просто загрузка одного бита — это значит, что вам придётся переписать всё отображение дат и код разбора, чтобы поддерживать оба формата нумерации. Я думаю, это займёт несколько дней. Далее, если вы работаете над клоном Excel, вы увидите все сложности работы с датами. Когда Excel конвертирует числа в даты? Почему «1/31» [в американской системе дат — прим. перев.] интерпретируется как 31 января этого года, а «1/50» — как 1 января 1950 года? Все эти тонкие особенности поведения нельзя полностью специфицировать, не написав документ, по объёму информации сравнимый с исходными текстами Excel’я [не согласен; это особенности интерфейса, а не формата файла — прим. перев.].

И это только первая из сотен записей BIFF, которые вам придётся поддерживать, и одна из простейших. Многие из них настолько сложны, что способны смутить даже умелого программиста.

Из этого только один вывод. Выпустить формат файлов Office — это полезно и для Microsoft, и для её продукта, но это не делает импорт или сохранение в файлы Office проще. Программы Office безумно сложны и многогранны, и невозможно реализовать только 20% наиболее популярных функций и осчастливить 80% народа. Спецификация двоичных файлов, по сути, сохранит только несколько минут, потраченных на «ковыряние» в чрезвычайно сложной системе.

Да, я обещал обходные пути. Хорошая новость: для большинства видов ПО писать чтение или запись документов Office — неверное решение. Есть две больших альтернативы: заставить Office делать всю грязную работу за вас, либо воспользоваться более простыми форматами.

Заставить Office делать грязную работу за вас. Word и Excel завязаны на сложных объектных моделях, основанных на автоматизации COM, что позволяет программно делать всё, что угодно. Во многих ситуациях проще будет использовать код Office, чем пытаться реализовать его с нуля. Вот несколько примеров.

  1. У вас есть веб-приложение, которое выводит файлы Office в формате PDF. Я бы это реализовал так: несколько строк на VBA Word’а загружают файл и сохраняют его через экспортёр PDF, встроенный в Word 2007. Этот код можно запустить напрямую, например, из ASP или ASP.NET под IIS. И это будет работать. Первый раз Word будет запускаться несколько секунд. Дальше будет быстрее — подсистема COM держит Word в памяти ещё несколько секунд на случай, если он вдруг потребуется ещё раз. Всё это достаточно быстро для веб-приложения.
  2. То же самое, но хостинг на Linux. Купи сервер на Windows 2003, установи на него лицензионный Word и настрой веб-службу, которая будет делать всё это. Полдня работы на C# и ASP.NET.
  3. То же самое, но требуется масштабируемость. Перед n машинами, описанными на 2 шаге, поставь балансировщик нагрузки. Программирование не требуется вообще.

Такой подход работает для большинства офисных задач, которые могут выполняться на вашем сервере. Например:

  • Открыть книгу Excel, записать данные во входные ячейки, пересчитать и получить результат в выходной ячейке.
  • Использовать Excel для генерации диаграмм в формате GIF.
  • Вытащить любую информацию из любой таблицы, не думая и минуты о форматах файлов.
  • Сконвертировать файл Excel в формат CSV (другой подход — использовать ODBC-драйверы Excel и вытащить данные через SQL-запрос).
  • Редактировать документы Word’а.
  • Заполнять формы Word’а.
  • Конвертировать данные между десятками разных форматов, которые поддерживаются Office’ом.

Во всех этих случаях есть способы сообщить объектам Officе, что они работают не в интерактивном режиме и перерисовывать экран не требуется. Кстати, если вы хотите идти этим путём, есть несколько ловушек, так что перед тем, как начать, прочитайте базу знаний Microsoft.

Записывать файлы в более простые форматы. Если вам требуется программно создавать документы, читаемые в Office, есть много других форматов, которые Office уверенно откроет, не пропустив ни байта.

  • Если вам нужно переводить табличные данные в Excel, попробуйте CSV.
  • Если нужны табличные расчёты, которые CSV не поддерживает, формат WK1 (Lotus 1–2–3) намного проще и открывается Excel’ем.
  • Если очень-очень нужно создавать именно файлы Excel’я, найдите очень старую версию… например, версию 3.0, в которой нет всех этих составных документов — и сохраните минимальный файл, в котором есть только те функции, которые вам нужны. В этом файле будет тот минимум BIFF-записей, которые вам потребуется записывать; так что вам придётся реализовать только эту часть спецификации.
  • Если нужно взаимодействие с Word’ом, можно использовать HTML. Word хорошо открывает его.
  • А если нужно сложное оформление, ваш выбор — RTF. Всё, что есть в Word, можно записать в RTF. Но это текстовый формат, а не двоичный — так что можно заменить часть данных, и файл останется корректным. Например, создаёте в Word’е красиво отформатированный документ с «заглушками» на месте данных, и с помощью простой текстовой замены подменяете их на лету. Этот RTF будет отлично открываться в любой версии Word.

В любом случае, если вы действительно собираетесь создать конкурента Office, который будет считывать и записывать все документы Office, у вас впереди тысячи человеко-лет работы. А если нет — считывание и запись двоичных форматов Office будет самым трудоёмким этапом в вашей работе, но без него вполне можно обойтись.

Personal tools