Как создать и заполнить справочник в 1С из текстового файла с разделителями?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Архитектурные ограничения: создание структуры метаданных и создание элементов

Проанализируем базовый вопрос: можно ли пользовательской внешней обработкой создать новый справочник и добавить в него произвольные реквизиты? Ответ платформы 1С — в режиме «1С:Предприятие» программно создать объект метаданных невозможно.

Рассмотрим ключевые особенности архитектуры 1С:

  1. Статичность метаданных: Структура объектов (справочники, документы, реквизиты, табличные части) создается и конфигурируется разработчиком исключительно в «Конфигураторе». В режиме работы пользователя модель метаданных фиксирована. Любое изменение схемы данных требует монопольного обновления базы данных или выполнения пакетных скриптов через запуск конфигуратора (например, выгрузка в XML через параметр /DumpConfigToFiles, правка файлов и загрузка через /LoadConfigFromFiles с последующим /UpdateDBCfg).
  2. Разделение понятий: Как справедливо замечено в обсуждении, создание самого объекта метаданных и создание записей (элементов) справочника — это разные операции. В пользовательском сеансе мы можем только заполнять справочник новыми элементами, используя уже существующую в конфигурации структуру полей.

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

  1. Планы видов характеристик (ПВХ): Использование типовой подсистемы «Дополнительные реквизиты и сведения» из БСП (Библиотеки стандартных подсистем), где состав свойств настраивается пользователем без изменения конфигурации.
  2. Универсальное хранилище: Запись дополнительных данных в подчиненный регистр сведений по схеме «объект — свойство — значение» либо хранение дополнительных параметров в реквизите типа «Строка неограниченной длины» в формате JSON.

Почему нельзя использовать прямые SQL-запросы (INSERT)

В процессе обсуждения нередко возникает предложение обойти механизмы платформы и сделать прямую вставку через INSERT в таблицы СУБД. Выясним причину, почему такой подход категорически не рекомендуется:

  1. Нарушение лицензионного соглашения: Прямая модификация таблиц СУБД 1С без использования штатных механизмов платформы запрещена вендором.
  2. Сбой ссылочной целостности: Платформа управляет генерацией уникальных идентификаторов (GUID), внутренними номерами версий и системными полями. При прямой вставке легко нарушить целостность данных.
  3. Кэширование и бизнес-логика: При прямом запросе не очищается кэш объектов платформы на сервере 1С, а также не отрабатывают события модулей объектов (ПередЗаписью, ПриЗаписи), проверки уникальности кодов и заполнения обязательных реквизитов.

Способы чтения текстового файла с разделителями

Рассмотрим, как прочитать текстовый файл, в котором строки содержат данные с разделителем (например, решетка #).

Вариант 1: Использование объекта ЧтениеCSV

Наиболее надежным и производительным инструментом платформы для файлов с разделителями является специализированный объект ЧтениеCSV. Он корректно обрабатывает экранирование, строки в кавычках и внутренние переносы строк.


Функция ПрочитатьФайлЧерезCSV(ПолноеИмяФайла)
    ТаблицаДанных = Новый ТаблицаЗначений;
    ТаблицаДанных.Колонки.Добавить("Артикул", Новый ОписаниеТипов("Строка"));
    ТаблицаДанных.Колонки.Добавить("Наименование", Новый ОписаниеТипов("Строка"));
    
    ПараметрыЧтения = Новый ПараметрыЧтенияCSV;
    ПараметрыЧтения.РазделительПолей = "#";
    ПараметрыЧтения.СимволМаскировки = """";
    
    ФайлCSV = Новый ЧтениеCSV;
    ФайлCSV.Открыть(ПолноеИмяФайла, ПараметрыЧтения);
    
    // Пропускаем строку заголовков, если она есть в файле
    СтрокаЗаголовка = ФайлCSV.Прочитать();
    
    Пока Истина Цикл
        МассивДанных = ФайлCSV.Прочитать();
        Если МассивДанных = Неопределено Тогда
            Прервать;
        КонецЕсли;
        
        Если МассивДанных.Количество() >= 2 Тогда
            НоваяСтрока = ТаблицаДанных.Добавить();
            НоваяСтрока.Артикул = СокрЛП(МассивДанных[0]);
            НоваяСтрока.Наименование = СокрЛП(МассивДанных[1]);
        КонецЕсли;
    КонецЦикла;
    
    ФайлCSV.Закрыть();
    Возврат ТаблицаДанных;
КонецФункции

Вариант 2: Потоковое чтение через ЧтениеТекста и СтрРазделить

Если файл не содержит сложных экранированных кавычек, можно использовать потоковое чтение через ЧтениеТекста. В отличие от объекта ТекстовыйДокумент, который загружает весь объем файла в оперативную память, ЧтениеТекста читает файл строка за строкой, предотвращая переполнение памяти.

Для разделения строки на части разберем использование функции СтрРазделить() вместо связки СтрЗаменить() и СтрПолучитьСтроку(), так как замена разделителя на перевод строки дает сбой, если в данных уже встречаются символы переноса.


Функция ПрочитатьФайлЧерезЧтениеТекста(ПолноеИмяФайла)
    ТаблицаДанных = Новый ТаблицаЗначений;
    ТаблицаДанных.Колонки.Добавить("Артикул", Новый ОписаниеТипов("Строка"));
    ТаблицаДанных.Колонки.Добавить("Наименование", Новый ОписаниеТипов("Строка"));
    
    ТекстовыйФайл = Новый ЧтениеТекста;
    ТекстовыйФайл.Открыть(ПолноеИмяФайла, КодировкаТекста.UTF8);
    
    // Пропускаем первую строку с именами реквизитов
    ПерваяСтрока = ТекстовыйФайл.ПрочитатьСтроку();
    
    ТекСтрока = ТекстовыйФайл.ПрочитатьСтроку();
    Пока ТекСтрока <> Неопределено Цикл
        Если Не ПустаяСтрока(СокрЛП(ТекСтрока)) Тогда
            МассивЗначений = СтрРазделить(ТекСтрока, "#", Истина);
            Если МассивЗначений.Количество() >= 2 Тогда
                НоваяСтрока = ТаблицаДанных.Добавить();
                НоваяСтрока.Артикул = СокрЛП(МассивЗначений[0]);
                НоваяСтрока.Наименование = СокрЛП(МассивЗначений[1]);
            КонецЕсли;
        КонецЕсли;
        ТекСтрока = ТекстовыйФайл.ПрочитатьСтроку();
    КонецЦикла;
    
    ТекстовыйФайл.Закрыть();
    Возврат ТаблицаДанных;
КонецФункции

Создание и запись элементов справочника с оптимизацией транзакций

После получения массива или таблицы данных перейдем к их сохранению в базу данных 1С. Запись каждого элемента в отдельности выполняется медленно, так как СУБД открывает транзакцию на каждый объект. Чтобы ускорить загрузку больших файлов, объединим запись элементов в транзакции порциями по 1 000–5 000 штук.

Посмотрим на пример заполнения справочника Номенклатура:


Процедура ЗагрузитьДанныеВБазу(ТаблицаДанных)
    РазмерПорции = 1000;
    Счетчик = 0;
    
    НачатьТранзакцию();
    
    Попытка
        Для Каждого СтрДанных Из ТаблицаДанных Цикл
            // Создаем новый элемент справочника
            НовыйЭлемент = Справочники.Номенклатура.СоздатьЭлемент();
            НовыйЭлемент.Артикул = СтрДанных.Артикул;
            НовыйЭлемент.Наименование = СтрДанных.Наименование;
            
            // Записываем объект
            НовыйЭлемент.Записать();
            
            Счетчик = Счетчик + 1;
            
            // Фиксируем порцию данных для оптимизации
            Если Счетчик % РазмерПорции = 0 Тогда
                ЗафиксироватьТранзакцию();
                НачатьТранзакцию();
            КонецЕсли;
        КонецЦикла;
        
        // Фиксируем оставшиеся элементы
        ЗафиксироватьТранзакцию();
        
    Исключение
        ОтменитьТранзакцию();
        ВызватьИсключение "Ошибка при загрузке данных: " + ОписаниеОшибки();
    КонецПопытки;
КонецПроцедуры

Таким образом, правильный алгоритм решения задачи состоит из двух этапов: предварительное создание метаданных нужного справочника в «Конфигураторе» и реализация обработки, выполняющей потоковое чтение файла (через ЧтениеCSV или ЧтениеТекста) с пакетной записью элементов справочника в базу данных.

← На главную