В процессе автоматизации учета часто возникает задача синхронизации файловой структуры на сервере или локальном компьютере с объектами информационной базы 1С. Например, когда изображения или документация хранятся в папках, названия которых соответствуют кодам номенклатуры. В этой статье мы подробно разберем, как реализовать механизм получения иерархии папок Windows и автоматизировать привязку путей к справочнику номенклатуры.
Основным инструментом для работы с файловой системой в 1С является метод НайтиФайлы. Проанализируем стандартный подход к реализации рекурсивного обхода. Задача состоит в том, чтобы зайти в каждую подпапку и выполнить определенное действие (в нашем случае — поиск номенклатуры). Рассмотрим пример реализации процедуры на стороне сервера.
Для начала создадим функцию, которая будет принимать путь к исходному каталогу и вызывать саму себя для каждой найденной вложенной папки. Это классический пример рекурсии.
&НаСервере
Процедура ОбходПапокРекурсивно(ПутьКаталога)
// Получаем массив всех объектов в текущем каталоге
НайденныеФайлы = НайтиФайлы(ПутьКаталога, "*");
Для каждого Файл Из НайденныеФайлы Цикл
Если Файл.ЭтоКаталог Тогда
// Выполняем полезную работу: сопоставление с номенклатурой
ОбработатьНайденнуюПапку(Файл);
// Рекурсивный вызов для вложенных папок
ОбходПапокРекурсивно(Файл.ПолноеИмя);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
В данном коде метод НайтиФайлы возвращает объекты типа Файл, которые содержат полезные свойства: Имя, ПолноеИмя, ЭтоКаталог. Использование рекурсии позволяет нам "провалиться" на любую глубину вложенности папок Windows.
Разберем конкретный кейс: имя папки — это код товара в 1С. Если мы находим такую папку, нам нужно записать её полный путь в дополнительный реквизит соответствующей номенклатуры. Проанализируем, как правильно организовать этот процесс внутри цикла обхода.
Важный момент: поиск объекта в базе данных внутри цикла (через НайтиПоКоду) может существенно замедлить работу при большом количестве папок. Однако для понимания логики рассмотрим сначала простой вариант, а затем перейдем к оптимизации.
&НаСервере
Процедура ОбработатьНайденнуюПапку(ОбъектПапка)
ИмяПапки = ОбъектПапка.Имя;
ПутьКПапке = ОбъектПапка.ПолноеИмя;
// Ищем номенклатуру, код которой совпадает с именем папки
СсылкаНом = Справочники.Номенклатура.НайтиПоКоду(ИмяПапки);
Если НЕ СсылкаНом.Пустая() Тогда
ОбъектНом = СсылкаНом.ПолучитьОбъект();
// Находим нужный дополнительный реквизит
СвойствоПуть = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("ПутьКФото", Истина);
// Работаем с табличной частью дополнительных реквизитов
СтрокаТЧ = ОбъектНом.ДополнительныеРеквизиты.Найти(СвойствоПуть, "Свойство");
Если СтрокаТЧ = Неопределено Тогда
СтрокаТЧ = ОбъектНом.ДополнительныеРеквизиты.Добавить();
СтрокаТЧ.Свойство = СвойствоПуть;
КонецЕсли;
Если СтрокаТЧ.Значение <> ПутьКПапке Тогда
СтрокаТЧ.Значение = ПутьКПапке;
Попытка
ОбъектНом.Записать();
Исключение
Сообщить("Ошибка при записи объекта " + ОбъектНом + ": " + ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Для того чтобы запустить процесс, пользователю необходимо выбрать стартовую папку. Выясним, как правильно вызвать диалог выбора каталога на управляемых формах. Рассмотрим обработчик события начала выбора для реквизита на форме.
&НаКлиенте
Процедура ВыбратьКаталог(Элемент, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.ВыборКаталога);
Диалог.Заголовок = "Выберите папку для сканирования";
Если Диалог.Выбрать() Тогда
Объект.ПутьККаталогу = Диалог.Каталог;
КонецЕсли;
КонецПроцедуры
Обратите внимание, что объект ДиалогВыбораФайла работает только на стороне клиента. После выбора пути управление передается серверной процедуре для выполнения обхода.
Если в вашей структуре тысячи папок, поиск номенклатуры по одной в цикле создаст избыточную нагрузку на сервер БД. Рассмотрим, как ускорить этот процесс. Вместо того чтобы искать номенклатуру на каждой итерации рекурсии, мы можем сначала собрать все имена папок в один массив (или таблицу значений), а затем выполнить один запрос к базе данных.
Алгоритм оптимизации выглядит следующим образом:
ТаблицаЗначений.Номенклатура.Посмотрим на пример формирования таблицы данных:
// Пример заполнения таблицы перед запросом
ТЗ_Папки = Новый ТаблицаЗначений;
ТЗ_Папки.Колонки.Добавить("КодДляПоиска", Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(50)));
ТЗ_Папки.Колонки.Добавить("ПолныйПуть", Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(500)));
// В рекурсии вместо поиска в БД делаем так:
НоваяСтр = ТЗ_Папки.Добавить();
НоваяСтр.КодДляПоиска = Файл.Имя;
НоваяСтр.ПолныйПуть = Файл.ПолноеИмя;
Иногда стандартный НайтиФайлы может работать медленно на огромных сетевых ресурсах. Проанализируем альтернативные варианты:
Новый COMОбъект("Scripting.FileSystemObject") и обращаемся к коллекции SubFolders. Это позволяет получать доступ к метаданным папок без глубокого сканирования содержимого.TREE /AD /F > result.txt можно мгновенно выгрузить всю структуру папок в текстовый файл, который затем легко прочитать и распарсить средствами 1С. Это особенно эффективно для очень ветвистых структур.Get-ChildItem. Результат можно получить сразу в формате CSV или JSON, что упрощает загрузку в 1С.При работе с файловой системой Windows в 1С важно учитывать права доступа. Рассмотрим ситуации, которые могут привести к ошибкам:
НайтиФайлы может вызвать исключение. Всегда заключайте вызов в блок Попытка...Исключение.Проанализировав все вышеперечисленные методы, мы видим, что задача получения иерархии папок Windows в 1С решается достаточно гибко. Выбор конкретного метода зависит от объема данных и требуемой скорости обработки. Для небольших структур идеально подходит рекурсия с НайтиФайлы, а для промышленных масштабов лучше использовать предварительный сбор данных в массив и пакетную обработку через запросы.