Есть так называемые контейнерные файлы: то есть файлы, содержащие
внутри себя несколько файлов, которые к тому же могут быть разбиты по дереву
подкаталогов. Примерами таких файлов могут служить практически все файлы
MS Office. Кем-то совершенно случайно было обнаружено, что такой-же структурой
обладают и файлы конфигурации 1С Предприятия - 1cv7.md. Для популярного файлового
менеджера FAR существует плагин для просмотра
и редактирования таких файлов, скачать который можно
тут (32 Kb). Родина этого плагина находится по адресу
Для желающих получить более человечное представление внутренней структуры MD сделана утилита gcomp.
Этот файл разбит на множество секций, каждая из которых взята в фигурные кавычки. Секции могут быть вложенными. Внутри секции может находиться несколько параметров, разделенных запятыми. Секции одного вида имеют одинаковый набор параметров. Все секции имеют идентификаторы. Эти идентификаторы записаны в первом параметре любой секции. Если секция самого верхнего уровня, то она имеет текстовый идентификатор, обозначающий, какого типа метаданные описаны в этой секции. Например, у констант секция называется Consts, у справочников - SbCnts, у нумераторов документов - DocNumRef, и т. д. Если же секция содержит в себе описание какого-то конкретного объекта метаданных, то идентификатор, как правило, цифровой. Для тех объектов метаданных, которым можно сопоставить некий файл в базе данных, этот идентификатор совпадает с номером файла. Например, справочник "Номенклатура" в комплексной конфигурации имеет идентификатор 33 и файл sc33.dbf.
Рассмотрим строение секции на примере справочника "Номенклатура". Первым полем, как уже было сказано, является идентификатор. Вторым - тот идентификатор, который задан в конфигураторе. Далее идут комментарий и синоним, а так же другие параметры справочника, такие как длина кода, наименование, подчиненность, вид основного представления, и т. д.
Затем идет секция описания параметров, называется она "Param", и вся состоит из вложенных секций-параметров. В каждом параметре идет идентификатор, затем название в конфигураторе, комментарий с синонимом, тип данных (U-Неопределенный, N-Число, S-Строка, D-Дата, B-Справочник, O-Документ, E-перечисление, T-Счет, P-ПланСчетов, K-ВидСубконто, C-Календарь, A-ВидРасчета), и ряд параметров, характерных для данного типа данных (длина, неотрицательность, периодичность, индексация, и т. д.).
И последняя секция - секция форм списков ("Form"). Здесь описаны формы списка нашего справочника. В данной секции так же присутствуют числовой идентификатор формы списка, идентификатор с синонимом и комментарием, как задано в конфигураторе. Например в моей конфигурации, для формы списка "ФормаСписка" идентификатор 34, а для списка "ДляПодбора" - 549.
GUIDData - это поток, на основании которого 1С определяет, является ли загружаемая конфигурация прямым наследником текущей. Если в него вглядеться в процессе его изменения, то становится ясным, что при каждом сохранении в начало файла (со смещением 20) дописывается кусочек из 16-ти байт, а в конце те же 16 байт удаляются. То есть получается некое FIFO.
Из этого можно сделать несколько выводов.
Вывод первый. Если мы в конфигуратор загрузили (в режиме "загрузить измененную конфигурацию") конфигурацию А1, и нажали кнопку "Сохранить", то в результате мы получим уже другую конфигурацию (назовем ее Б1), которая будет отличаться от А1 составом потока GUIDData. Соответственно, если потом внести изменения в конфигурацию А1 (получим А2), и попытаться загрузить А2 в Б1, то мы получим сообщение о том, что "Загружаемая конфигурация не является потомком текущей".
Описываемый эффект часто возникает в ситуации, когда программист сидит дома и пишет конфигурацию, а раз в три дня приезжает к клиенту и загружает ее как измененную. Обычно подобный эффект вызывает изумление. В данном конкретном случае, разумеется, подобное сообщение можно игнорировать. Если же экспериментировать не хочется, то для избежания подобных сообщений сразу после создания конфигурации Б1 ее нуно загрузить поверх А1 (Получим В1), и уже дальнейшее редактирование производить в В1.
Вывод второй. При коллективной раработке с помощью GComp, поток GUIDData можно полностью игнорировать и не коммитить вообще. Ибо проблему уникальности идентификаторов метаданных при коллективной разработке решают другими способами. Однако можно и коммитить - хуже не будет. А вдобавок, если коммитить GUIDData, то по истории одного этого файла можно отследить все изменения, сделанные в конфигурации.
Вывод третий, на первый взгляд парадоксальный. Поскольку длина потока GUIDData ограничена (32020 байт), а как уже было сказано, ротация элементов в нем происходит по принципу FIFO, то становится очевидным, что после определенного числа сохранений (а именно (32020-20) / 16 = 2000) 1С перестает узнавать прямых потомков конфигурации.
Справочник как метаданные - структура сложная. Наверное, в компенсацию за простоту хранения данных. :)
Метаданные для справочника, кроме файла Main Metadata Stream, находятся аж в трех папках. Это папки Subconto, SubFolder и SubList. Как можно легко понять из названий, там находятся формы элемента, группы и списков соответственно.
Внутри каждой папки находится куча папок с именами типа Subconto_NumberNNN, где NNN - идентификатор. Для папок Subconto и SubFolder идентификатор совпадает с идентификатором самого справочника, а для папки SubList у каждой формы списка свой идентификатор (указан в Main Metadata Stream). В дополнение скажу, что в каждой папке с номером-идентификатором, есть только одна подпапка WorkBook, в которой уже и находится то, что мы ищем.
Таким образом, описание формы элемента справочника "Номенклатура" можно найти в папке
Содержимое каждой папки WorkBook типовое. Она содержит максимум пять типов файлов.
Пройдемся теперь по всем каталогам и выясним их назначение. Внутри каждого каталога структура практически одинаковая: множество нумерованных подкаталогов, содержащих ту или иную часть метаданных. При этом номера соответствуют идентификаторам объектов из Main Metadata Stream.
Итак:
У читающего все это может возникнуть резонный вопрос: а зачем все это нужно на практике, какое народо-хозяйственное значение? Разумеется, все не просто так.
Во-первых, кому-то просто может оказаться интересно: что же там понапихано в двенадцати (уже семнадцати) мегабайтах комплексной конфигурации? И, возможно, этот объем можно как-то уменьшить, не снижая функциональности?
Во-вторых, иногда, после каких-то сбоев, при попытке запустить 1С:Предприятие
возникают ошибки с непонятной диагностикой навроде:
В-третьих, как оказывается, система защиты файла 1cv7.md паролем от чтения и записи не такая уж и абсолютная, как может показаться с первого взгляда.
В-четвертых, получив доступ к структуре данных, можно написать стороннюю программу обмена данных с 1С, которая будет работать с любой конфигурацией.
В-пятых, зная структуру внешне монолитного файла конфигурации, можно организовать совместный доступ к нему несколькими разработчиками.
Да и вообще, умный человек найдет применение данному знанию.
Во-первых, надо четко понимать, что контейнерный файл - своеобразная база данных. А базы данных имеют обыкновение хранить в себе пустые места. Например, в dbf удаленные записи не удаляются, а освобождаются для последующих записей. md - не dbf, но и в нем при определенных действиях возникают "дырки".
Сохранение файла 1cv7.md может происходить двума способами. Простое сохранение без лишних вопросов происходит, если изменения коснулись только в модулей, а так же печатных и экранных форм. Сохранение с анализом изменений и возможной реорганизацией БД происходит в тех случаях, когда она предполагает изменение структуры данных. Простейший способ этого добиться, не изменяя конфигурацию - добавить и тут же удалить новую константу или реквизит любого справочника/документа. Можно так же зайти в свойства любого реквизита или объекта, и в комментарии добавить и тут же удалить пробел (я именно так и делаю).
Так вот: только после сохранения с анализом изменений мы можем получить 1cv7.md минимального размера для текущей функциональности.
Иногда мне кажется, что я не всегда внятно излагаю :), поэтому вот тут можно посмотреть описание того же эффекта другими людьми.
Вместо сохранения измененной конфигурации - можно еще перепаковать конфигурацию gcomp'ом
Во-вторых, как уже было сказано чуть выше, присутствие или отсутствие файлов container.profile никак не влияет на функциональность конфигурации. Соответственно, мы можем удалить все такие файлы с помощью плагина к FAR'у, потом загрузить получившуюся конфигурацию как измененную, сохранить, и получить выигрыш по 512 байт на каждый такой файл.
В качестве необходимого дополнения хочется добавить, что эти файлы возникают в каталогах сами собой, когда вы начинаете редактировать соответствующие им объекты метаданных.
Если вам лень перебирать ручками все папки в поисках потоков Container.Profile - воспользуйтесь утилитой gcomp, и с ее помощью перепакуйте конфигурацию с ключом --no-profiles.
В-третьих, после вдумчивого рассмотрения всех каталогов, я обнаружил одну забавную особенность каталога Journal. В нем оказались каталоги с идентификаторами, для которых не существует форм журналов. Однако, эти идентификаторы порой совпадали с идентификаторами самих журналов. Вероятно, еще в версии 7.0 (я знаком с ней весьма поверхностно, поэтому не могу утверждать наверняка), журналы документов могли иметь только одну форму списка. Очевидно, что эта форма имела тот же идентификатор, что и сам журнал. Когда же в версии 7.5 появилась возможность заводить несколько форм для одного журнала, идентификаторы форм, очевидно, пришлось поменять. Однако при преобразовании конфигурации из старого формата "старые" формы, видимо, забыли удалить. Эти формы можно легко опознать по идентификатору - они все меньше 900. В качестве дополнительного подтверждения того, что эти каталоги абсолютно излишни на текущий момент, могу указать на то, что в соответствующем Container.Contents из каталога Journal нет ни одного упоминания о том, что такие папки должны присутствовать.
В комплексной 2.6 таких "забытых" форм 13 штук. Если учесть, что каждая состоит как минимум из пяти файлов и одного каталога, то нетрудно посчитать, что их удаление принесет нам 6 * 13 * 512 = килобайт 40 как минимум. А за счет того, что экранные формы меньше трех кластеров почти никогда не занимают, реальный выигрыш наверняка окажется вдвое значительнее.
И здесь поможет перепаковка конфигурации gcomp'ом. И даже никаких опций не нужно.
Более детальное исследование экранных форм показало, что для каждого объекта на форме хранится название того слоя, которому этот элемент принадлежит. По умолчанию, название единственного слоя - "Основной". Если слой один, а объектов на форме два десятка, то постым переименованием слоя в "О", можно добиться экономии 7 * 20 = 140 байт. И если повезет, форма станет занимать на один 512-ти байтный блок меньше. Если Вам кажется, что это мелочь - вспомните, сколько экранных форм в конфигурации.
Здесь готового решения нету. Однако теоретически можно написать скриптик, который переколбасит разобранную gcomp'ом конфигурацию, после чего собрать ее обратно.
Вспомним о пустых таблицах. Они занимают один кластер, то есть, 512 байт. Просто удивительно, насколько их много, особенно в формах журналов, обработках и формах списков справочников (то есть там, где они абсолютно не нужны).
И здесь у gcomp'а нашлась опция. --no-empty-mxl называется.
Что касается справочников. У справочника, как мы помним, есть аж три формы: списка, группы и элемента. Так вот, если в справочнике один уровень, то форма группы, очевидно, не нужна. Если справочник редактируется только в списке, то не нужна еще и форма элемента. И если первую ситуацию 1С отслеживает и предлагает удалить неиспользуемую форму группы, то ненужную форму элемента не только нельзя удалить штатными способами, но она еще и автоматически будет создана при первой попытке в нее войти (что-то MS запахло, не правда ли?). Удалить такую форму можно только хирургически, читай, с помощью плагина DocFile Browser. Главное, не забыть удалить ссылку на удаленный каталог в Subconto\Container.Contents
Данная тонкая хирургия gcomp'у неподвластна.
Еще одно поле для деятельности - картинки. Для gcomp'а создан скрипт (show_pics), который показывает статистику по используемым (и главное - по неиспользуемым) картинкам. А картинки могут быть большими, очень большими, и воистину огромными.
Однако самый эффективный способ уменьшения размера конфигурации - удаление лишнего функционала и оптимизация существующего. Комплексная в этом смысле - непаханное поле. Впрочем, это уже совсем другая история...