При интеграции систем или разовом переносе данных часто возникает задача: взять текстовый файл с разделителями и загрузить из него информацию в систему 1С. Разберем подробно, возможно ли автоматически создать структуру справочника «на лету» в режиме пользователя, какие архитектурные ограничения платформы следует учитывать и как правильно реализовать разбор файла и программное создание элементов.
Проанализируем базовый вопрос: можно ли пользовательской внешней обработкой создать новый справочник и добавить в него произвольные реквизиты? Ответ платформы 1С — в режиме «1С:Предприятие» программно создать объект метаданных невозможно.
Рассмотрим ключевые особенности архитектуры 1С:
/DumpConfigToFiles, правка файлов и загрузка через /LoadConfigFromFiles с последующим /UpdateDBCfg).Если задача требует хранения произвольного набора свойств, которые заранее неизвестны, используют штатные механизмы:
В процессе обсуждения нередко возникает предложение обойти механизмы платформы и сделать прямую вставку через INSERT в таблицы СУБД. Выясним причину, почему такой подход категорически не рекомендуется:
ПередЗаписью, ПриЗаписи), проверки уникальности кодов и заполнения обязательных реквизитов.Рассмотрим, как прочитать текстовый файл, в котором строки содержат данные с разделителем (например, решетка #).
Наиболее надежным и производительным инструментом платформы для файлов с разделителями является специализированный объект ЧтениеCSV. Он корректно обрабатывает экранирование, строки в кавычках и внутренние переносы строк.
Функция ПрочитатьФайлЧерезCSV(ПолноеИмяФайла)
ТаблицаДанных = Новый ТаблицаЗначений;
ТаблицаДанных.Колонки.Добавить("Артикул", Новый ОписаниеТипов("Строка"));
ТаблицаДанных.Колонки.Добавить("Наименование", Новый ОписаниеТипов("Строка"));
ПараметрыЧтения = Новый ПараметрыЧтенияCSV;
ПараметрыЧтения.РазделительПолей = "#";
ПараметрыЧтения.СимволМаскировки = """";
ФайлCSV = Новый ЧтениеCSV;
ФайлCSV.Открыть(ПолноеИмяФайла, ПараметрыЧтения);
// Пропускаем строку заголовков, если она есть в файле
СтрокаЗаголовка = ФайлCSV.Прочитать();
Пока Истина Цикл
МассивДанных = ФайлCSV.Прочитать();
Если МассивДанных = Неопределено Тогда
Прервать;
КонецЕсли;
Если МассивДанных.Количество() >= 2 Тогда
НоваяСтрока = ТаблицаДанных.Добавить();
НоваяСтрока.Артикул = СокрЛП(МассивДанных[0]);
НоваяСтрока.Наименование = СокрЛП(МассивДанных[1]);
КонецЕсли;
КонецЦикла;
ФайлCSV.Закрыть();
Возврат ТаблицаДанных;
КонецФункции
Если файл не содержит сложных экранированных кавычек, можно использовать потоковое чтение через ЧтениеТекста. В отличие от объекта ТекстовыйДокумент, который загружает весь объем файла в оперативную память, ЧтениеТекста читает файл строка за строкой, предотвращая переполнение памяти.
Для разделения строки на части разберем использование функции СтрРазделить() вместо связки СтрЗаменить() и СтрПолучитьСтроку(), так как замена разделителя на перевод строки дает сбой, если в данных уже встречаются символы переноса.
Функция ПрочитатьФайлЧерезЧтениеТекста(ПолноеИмяФайла)
ТаблицаДанных = Новый ТаблицаЗначений;
ТаблицаДанных.Колонки.Добавить("Артикул", Новый ОписаниеТипов("Строка"));
ТаблицаДанных.Колонки.Добавить("Наименование", Новый ОписаниеТипов("Строка"));
ТекстовыйФайл = Новый ЧтениеТекста;
ТекстовыйФайл.Открыть(ПолноеИмяФайла, КодировкаТекста.UTF8);
// Пропускаем первую строку с именами реквизитов
ПерваяСтрока = ТекстовыйФайл.ПрочитатьСтроку();
ТекСтрока = ТекстовыйФайл.ПрочитатьСтроку();
Пока ТекСтрока <> Неопределено Цикл
Если Не ПустаяСтрока(СокрЛП(ТекСтрока)) Тогда
МассивЗначений = СтрРазделить(ТекСтрока, "#", Истина);
Если МассивЗначений.Количество() >= 2 Тогда
НоваяСтрока = ТаблицаДанных.Добавить();
НоваяСтрока.Артикул = СокрЛП(МассивЗначений[0]);
НоваяСтрока.Наименование = СокрЛП(МассивЗначений[1]);
КонецЕсли;
КонецЕсли;
ТекСтрока = ТекстовыйФайл.ПрочитатьСтроку();
КонецЦикла;
ТекстовыйФайл.Закрыть();
Возврат ТаблицаДанных;
КонецФункции
После получения массива или таблицы данных перейдем к их сохранению в базу данных 1С. Запись каждого элемента в отдельности выполняется медленно, так как СУБД открывает транзакцию на каждый объект. Чтобы ускорить загрузку больших файлов, объединим запись элементов в транзакции порциями по 1 000–5 000 штук.
Посмотрим на пример заполнения справочника Номенклатура:
Процедура ЗагрузитьДанныеВБазу(ТаблицаДанных)
РазмерПорции = 1000;
Счетчик = 0;
НачатьТранзакцию();
Попытка
Для Каждого СтрДанных Из ТаблицаДанных Цикл
// Создаем новый элемент справочника
НовыйЭлемент = Справочники.Номенклатура.СоздатьЭлемент();
НовыйЭлемент.Артикул = СтрДанных.Артикул;
НовыйЭлемент.Наименование = СтрДанных.Наименование;
// Записываем объект
НовыйЭлемент.Записать();
Счетчик = Счетчик + 1;
// Фиксируем порцию данных для оптимизации
Если Счетчик % РазмерПорции = 0 Тогда
ЗафиксироватьТранзакцию();
НачатьТранзакцию();
КонецЕсли;
КонецЦикла;
// Фиксируем оставшиеся элементы
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение "Ошибка при загрузке данных: " + ОписаниеОшибки();
КонецПопытки;
КонецПроцедуры
Таким образом, правильный алгоритм решения задачи состоит из двух этапов: предварительное создание метаданных нужного справочника в «Конфигураторе» и реализация обработки, выполняющей потоковое чтение файла (через ЧтениеCSV или ЧтениеТекста) с пакетной записью элементов справочника в базу данных.