Как загрузить иерархический справочник из DBF-файлов 1С 7.7 в 1С 8 с сохранением структуры групп?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При переносе данных из устаревших версий «1С:Предприятия 7.7» в современную платформу «1С:Предприятие 8» разработчики часто сталкиваются с ситуацией, когда прямое подключение через COM-соединение (V77.Application) невозможно или нецелесообразно. Причинами могут быть разрядность серверов (x64), повреждение OLE-компонентов, отсутствие установленной платформы 7.7 на целевом сервере или требование работать напрямую с резервными копиями таблиц DBF.

В такой ситуации возникает задача прямого чтения таблиц баз данных 7.7. Разберем подробно, как устроена структура хранения данных в таблицах 1С 7.7, где искать соответствие таблиц и реквизитов, как закодированы ссылки на родительские группы и какими способами можно перенести иерархию справочника (например, «Номенклатура») в 1С 8.

Структура хранения данных в 1С 7.7: словарь 1Cv7.DD и таблицы справочников

Проанализируем организацию файлов базы данных формата DBF в 1С 7.7. В отличие от конфигураций на платформе 1С 8, где имена физических таблиц в СУБД формируются по внутренним идентификаторам метаданных, в 1С 7.7 вся карта соответствия объектов базы хранится в специальном текстовом файле словаря данных — 1Cv7.DD (Data Dictionary), расположенном в корне каталога информационной базы.

Каждому справочнику конфигурации соответствует отдельный файл с именем вида SC***.DBF, где *** — уникальный числовой идентификатор объекта. Открыв файл 1Cv7.DD в любом текстовом редакторе, найдем секцию нужного справочника. Например, для справочника «Номенклатура» описание будет выглядеть следующим образом:


#===============================================================================
#==ТАБЛИЦА : Справочник Номенклатура
#==ИМЯ     : SC84
#===============================================================================
Fields:
Field 1   : ID        : Char(9)   : Идентификатор объекта
Field 2   : PARENTID  : Char(9)   : Идентификатор родителя
Field 3   : CODE      : Char(10)  : Код
Field 4   : DESCR     : Char(100) : Наименование
Field 5   : ISFOLDER  : Numeric(1): ЭтоГруппа (1 - папка, 2 - элемент)
Field 6   : ISMARK    : Logical   : ПометкаУдаления

Рассмотрим ключевые служебные поля, отвечающие за построение иерархии:

  1. ID — уникальный идентификатор записи в таблице. Имеет тип Char(9) и представляет собой девятисимвольную строку в 36-ричной системе счисления (символы 0–9 и A–Z). Первые 6 символов кодируют порядковый номер записи, а последние 3 символа содержат код узла информационной базы (префикс распределенной ИБ).
  2. PARENTID — идентификатор родительской группы. Поле присутствует во всех справочниках с количеством уровней иерархии больше одного. Если элемент или группа находится в корне справочника (не имеет родителя), в поле PARENTID записывается пустой идентификатор: " 0 " (пять пробелов, ноль, три пробела).
  3. ISFOLDER — признак типа записи. Принимает числовое значение: 1 — запись является группой (папкой), 2 — запись является конечным элементом.
  4. ISMARK — признак пометки на удаление (логическое поле T / F или символ *).

Особенности и подводные камни при чтении DBF 7.7

Прежде чем приступать к загрузке данных в 1С 8, обратим внимание на важные технические нюансы:

  1. Кодировка таблиц: Таблицы DBF в 1С 7.7 традиционно сохраняются в кодировке DOS (CP866) или Windows (CP1251). При создании объекта XBase в платформе 1С 8 обязательно проверяем и задаем правильную кодировку, иначе все строковые реквизиты (наименования, артикулы) загрузятся с искажениями.
  2. Периодические реквизиты: В таблице SC***.DBF хранятся только непериодические реквизиты. Все периодические значения (например, цены, базовые единицы или периодические реквизиты) хранятся в общей таблице 1SCONST.DBF и связываются по условию OBJID = SC***.ID.
  3. Длинные строки и комментарии: Неограниченные текстовые строки выносятся в отдельный файл примечаний SC***.DBT либо в системную таблицу 1STRCNT.DBF.

Способ 1. Двухпроходное чтение с таблицей соответствия (Классический алгоритм)

Разберем наиболее надежный и простой в отладке алгоритм переноса иерархии. Проблема прямой последовательной загрузки из DBF заключается в том, что в файле дочерние элементы могут физически располагаться раньше, чем их группы-родители. Если попытаться сразу проставить родителя, нужного объекта в базе 1С 8 еще может не существовать.

Для решения этой задачи выполним загрузку в два этапа:

  1. Первый проход: Читаем файл SC***.DBF, создаем все группы и элементы в 1С 8 (группы создаем через Справочники.Номенклатура.СоздатьГруппу(), элементы — через Справочники.Номенклатура.СоздатьЭлемент()). Заполняем код, наименование и прочие базовые реквизиты, но поле Родитель оставляем пустым. В объекте Соответствие сохраняем связь: ключ — строковый ID из 7.7, значение — полученная Ссылка нового объекта 1С 8.
  2. Второй проход: Повторно перебираем записи файла DBF. Если значение поля PARENTID не равно пустому значению " 0 ", находим ссылку родителя в нашем объекте Соответствие и записываем реквизит Родитель у созданного объекта.

Посмотрим на программную реализацию данного способа на встроенном языке 1С:Предприятия 8:


Процедура ЗагрузитьНоменклатуруИзDBF_ДваПрохода(ПутьКФайлуDBF) Экспорт

    ФайлDBF = Новый XBase;
    ФайлDBF.Кодировка = КодировкаXBase.КодировкаDOS; // При необходимости меняем на КодировкаWindows
    ФайлDBF.ОткрытьФайл(ПутьКФайлуDBF);

    Если Не ФайлDBF.Открыта() Тогда
        ВызватьИсключение "Не удалось открыть файл таблицы 1С 7.7: " + ПутьКФайлуDBF;
    КонецЕсли;

    ТаблицаСсылок = Новый Соответствие; // Ключ - ID_77, Значение - Ссылка_8

    // --- Первый проход: создание всех групп и элементов ---
    ФайлDBF.Первая();
    Пока Не ФайлDBF.ВКонце() Цикл

        Идентификатор77 = СокрЛП(ФайлDBF.ID);
        ЭтоПапка        = (ФайлDBF.ISFOLDER = 1);
        Наименование    = СокрЛП(ФайлDBF.DESCR);
        КодЭлемента     = СокрЛП(ФайлDBF.CODE);
        ПометкаУдаления = (ФайлDBF.ISMARK = Истина);

        Если ЭтоПапка Тогда
            НовыйОбъект = Справочники.Номенклатура.СоздатьГруппу();
        Иначе
            НовыйОбъект = Справочники.Номенклатура.СоздатьЭлемент();
        КонецЕсли;

        НовыйОбъект.Наименование    = Наименование;
        НовыйОбъект.Код             = КодЭлемента;
        НовыйОбъект.ПометкаУдаления = ПометкаУдаления;

        // Дополнительно можно заполнить артикул, единицу и другие реквизиты
        Попытка
            НовыйОбъект.Записать();
            ТаблицаСсылок.Вставить(Идентификатор77, НовыйОбъект.Ссылка);
        Исключение
            Сообщить("Ошибка при создании объекта: " + Наименование + " (" + ОписаниеОшибки() + ")");
        КонецПопытки;

        ФайлDBF.Следующая();
    КонецЦикла;

    // --- Второй проход: расстановка связей иерархии ---
    ФайлDBF.Первая();
    Пока Не ФайлDBF.ВКонце() Цикл

        Идентификатор77 = СокрЛП(ФайлDBF.ID);
        РодительID77    = СокрЛП(ФайлDBF.PARENTID);

        // Проверяем, есть ли родитель (в 7.7 корень обозначается как "0" или пустая строка с пробелами)
        Если РодительID77 <> "0" И ЗначениеЗаполнено(РодительID77) Тогда
            
            СсылкаНаОбъект = ТаблицаСсылок.Получить(Идентификатор77);
            СсылкаНаРодителя = ТаблицаСсылок.Получить(РодительID77);

            Если СсылкаНаОбъект <> Неопределено И СсылкаНаРодителя <> Неопределено Тогда
                ОбъектДляИзменения = СсылкаНаОбъект.ПолучитьОбъект();
                Если ОбъектДляИзменения.Родитель <> СсылкаНаРодителя Тогда
                    ОбъектДляИзменения.Родитель = СсылкаНаРодителя;
                    Попытка
                        ОбъектДляИзменения.Записать();
                    Исключение
                        Сообщить("Не удалось установить родителя для: " + СсылкаНаОбъект);
                    КонецПопытки;
                КонецЕсли;
            КонецЕсли;

        КонецЕсли;

        ФайлDBF.Следующая();
    КонецЦикла;

    ФайлDBF.ЗакрытьФайл();
    Сообщить("Импорт номенклатуры с иерархией успешно завершен!");

КонецПроцедуры

Способ 2. Однопроходная загрузка с детерминированной генерацией UUID

Рассмотрим более продвинутый подход, который платформа 1С 8 позволяет реализовать благодаря механизму ПолучитьСсылку() по предопределенному объекту УникальныйИдентификатор.

Смысл метода заключается в том, что мы можем сформировать ссылку на объект еще до его физической записи в базу данных. Преобразуем строковый ID из 7.7 в корректный UUID (например, дополнив строку фиксированными нулями до 32 шестнадцатеричных символов или вычислив детерминированный хэш MD5). В результате при считывании строки файла мы сразу знаем как будущую ссылку самого элемента, так и готовую ссылку его родителя.

Посмотрим на пример генерации фиксированного идентификатора и создания объектов за один проход:


Функция ПолучитьUUID_Из_ID77(ID77)
    // ID77 содержит 9 символов. Дополним строку нулями до стандартного GUID формата 8-4-4-4-12
    СтрокаХэша = "00000000-0000-0000-0000-" + Прав("000000000000" + ВРег(СокрЛП(ID77)), 12);
    Возврат Новый УникальныйИдентификатор(СтрокаХэша);
КонецФункции

Процедура ЗагрузитьНоменклатуруИзDBF_ОдинПроход(ПутьКФайлуDBF) Экспорт

    ФайлDBF = Новый XBase;
    ФайлDBF.Кодировка = КодировкаXBase.КодировкаDOS;
    ФайлDBF.ОткрытьФайл(ПутьКФайлуDBF);

    Если Не ФайлDBF.Открыта() Тогда
        Возврат;
    КонецЕсли;

    ФайлDBF.Первая();
    Пока Не ФайлDBF.ВКонце() Цикл

        Идентификатор77 = СокрЛП(ФайлDBF.ID);
        РодительID77    = СокрЛП(ФайлDBF.PARENTID);
        ЭтоПапка        = (ФайлDBF.ISFOLDER = 1);

        // Получаем заранее вычисленную ссылку для текущего элемента
        ГУИД_Элемента = ПолучитьUUID_Из_ID77(Идентификатор77);
        СсылкаНаОбъект = Справочники.Номенклатура.ПолучитьСсылку(ГУИД_Элемента);

        Если ЭтоПапка Тогда
            НовыйОбъект = Справочники.Номенклатура.СоздатьГруппу();
        Иначе
            НовыйОбъект = Справочники.Номенклатура.СоздатьЭлемент();
        КонецЕсли;

        // Устанавливаем предопределенную ссылку
        НовыйОбъект.УстановитьСсылкуНового(СсылкаНаОбъект);

        НовыйОбъект.Наименование    = СокрЛП(ФайлDBF.DESCR);
        НовыйОбъект.Код             = СокрЛП(ФайлDBF.CODE);
        НовыйОбъект.ПометкаУдаления = (ФайлDBF.ISMARK = Истина);

        // Если есть родитель, сразу формируем на него ссылку
        Если РодительID77 <> "0" И ЗначениеЗаполнено(РодительID77) Тогда
            ГУИД_Родителя = ПолучитьUUID_Из_ID77(РодительID77);
            НовыйОбъект.Родитель = Справочники.Номенклатура.ПолучитьСсылку(ГУИД_Родителя);
        КонецЕсли;

        Попытка
            НовыйОбъект.Записать();
        Исключение
            Сообщить("Ошибка записи объекта: " + ОписаниеОшибки());
        КонецПопытки;

        ФайлDBF.Следующая();
    КонецЦикла;

    ФайлDBF.ЗакрытьФайл();

КонецПроцедуры

Альтернативные способы переноса без использования прямого DBF

Если разбор структуры файлов 1Cv7.DD кажется избыточным или требуется перенести сложные периодические реквизиты и подчиненные справочники, проанализируем типовые альтернативы:

  1. Конвертация данных 2.1 (КД 2): В конфигурацию 7.7 загружается внешняя обработка выгрузки V77Exp.ert, настраиваются правила обмена (ПКО, ПКС), и формируется стандартный XML-файл. На стороне 1С 8 файл читается обработкой УниверсальныйОбменДаннымиXML.epf. Этот метод автоматически обрабатывает иерархию любой глубины и не требует использования COM-соединения.
  2. Промежуточный экспорт в CSV/JSON: Если на машине с базой 7.7 есть возможность один раз запустить предприятие, можно написать простую обработку обхода справочника с помощью ВыбратьЭлементы() и выгрузить плоскую таблицу с полями ИД, ИД_Родителя, ЭтоГруппа, Код, Наименование. Это избавит от необходимости сопоставлять имена файлов таблиц через 1Cv7.DD.

Таким образом, понимание назначения полей PARENTID, ISFOLDER и формата идентификаторов 1С 7.7 позволяет быстро и корректно перенести любую сложную иерархическую структуру в 1С 8, используя стандартный объект XBase встроенного языка.

← На главную