Как перебрать папки внутренних документов и найти нужную подпапку в 1С?

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

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

Разберем подробно, почему стандартные файловые функции здесь не подходят, как правильно организовать обход подчиненных папок в иерархии справочника и как избежать типичных ошибок при сопоставлении наименований.

Файловая система или справочник: выясняем причину ошибки

Посмотрим на ситуацию, с которой начинается большинство подобных ошибок. Если попытаться применить функцию НайтиФайлы() к реквизиту формы, содержащему ссылку на справочник, функция не даст результата либо завершится аварийно, так как ожидает строковый путь к физическому диску (например, "C:\Storage\Docs"):


// Ошибочный подход: попытка передать ссылку на справочник в файловую функцию
МассивКаталогов = НайтиФайлы(ПутьКПапке, "*.*", Истина);

Если нам действительно нужно работать с физическими каталогами на диске или сетевом ресурсе, метод НайтиФайлы() вызывается исключительно со строковыми путями:


// Корректная работа с файловой системой
МассивФайлов = НайтиФайлы("D:\Data\Documents", "*", Истина);
Для Каждого Файл Из МассивФайлов Цикл
    Если Файл.ЭтоКаталог() Тогда
        Сообщить("Найден каталог: " + Файл.ПолноеИмя);
    КонецЕсли;
КонецЦикла;

Когда же переменная содержит ссылку на элемент прикладного объекта СправочникСсылка.ПапкиВнутреннихДокументов, задача переходит в плоскость работы с иерархическими справочниками 1С.

Обход подпапок через выборку данных

Для последовательного обхода всех подчиненных элементов и групп в платформе 1С предусмотрен метод менеджера справочника ВыбратьИерархически(). Проанализируем правильный порядок работы с этим методом:

  1. Инициализация выборки: передаем ссылку на родительскую папку первым параметром метода ВыбратьИерархически(Родитель).
  2. Позиционирование курсора: метод Следующий() перемещает указатель на очередную запись. Важно помнить, что до первого вызова Следующий() выборка не позиционирована, и обращение к ее полям (например, Выборка.Наименование) приведет к ошибке или вернет пустое значение.
  3. Получение ссылки: переменная выборки является объектом-итератором (СправочникВыборка). Чтобы сохранить ссылку на найденную папку, необходимо явно обращаться к свойству Выборка.Ссылка, а не присваивать саму выборку.

Рассмотрим пример кода с исправлением логических ошибок поиска:


&НаСервере
Функция НайтиПодпапкуПоИмени(РодительскаяПапка, ИскомоеИмя)
    
    НайденнаяПапка = Справочники.ПапкиВнутреннихДокументов.ПустаяСсылка();
    ИмяДляПоиска   = СокрЛП(ИскомоеИмя);
    
    // Получаем иерархическую выборку с фильтром по родителю
    Выборка = Справочники.ПапкиВнутреннихДокументов.ВыбратьИерархически(РодительскаяПапка);
    
    Пока Выборка.Следующий() Цикл
        // Пропускаем помеченные на удаление папки при необходимости
        Если Выборка.ПометкаУдаления Тогда
            Продолжить;
        КонецЕсли;
        
        // Очищаем строки от невидимых пробелов для корректного сравнения
        Если СокрЛП(Выборка.Наименование) = ИмяДляПоиска Тогда
            НайденнаяПапка = Выборка.Ссылка; // Получаем именно ссылку
            Прервать; // Прерываем цикл сразу после нахождения
        КонецЕсли;
    КонецЦикла;
    
    Возврат НайденнаяПапка;
    
КонецФункции

Обратите внимание на конструкцию Прервать. В исходных вариантах без прерывания цикла переменная состояния или сообщения об ошибке перезаписываются на каждой последующей итерации, из-за чего программа считает, что папка не найдена, даже если совпадение произошло в середине списка.

Оптимальные способы поиска: метод менеджера и запрос

Хотя последовательный перебор через ВыбратьИерархически() нагляден, при большом количестве вложенных папок он работает медленно. Рассмотрим более производительные решения.

1. Использование метода «НайтиПоНаименованию»

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


// Параметры: Наименование, ТочноеСоответствие, Родитель
НайденнаяПапка = Справочники.ПапкиВнутреннихДокументов.НайтиПоНаименованию(
    СокрЛП(ТекСтрока[ИндексКолонки]), 
    Истина, 
    ПутьКПапке
);

Если Не ЗначениеЗаполнено(НайденнаяПапка) Тогда
    Сообщить("Папка не найдена в указанном каталоге!");
Иначе
    Сообщить("Найдена папка: " + Строка(НайденнаяПапка));
КонецЕсли;

2. Поиск с помощью языка запросов (рекомендуемый вариант)

Запрос работает быстрее всего, позволяет сразу отсечь помеченные на удаление элементы и гибко настроить глубину поиска:

  1. Поиск только среди прямых потомков: используем условие Родитель = &Родитель.
  2. Поиск по всей иерархии любой вложенности: используем конструкцию Родитель В ИЕРАРХИИ(&Родитель).

Посмотрим на реализацию серверной функции поиска через запрос:


&НаСервере
Функция НайтиПапкуЗапросом(РодительскаяПапка, ИмяПодпапки, ИскатьВоВсехВложенных = Ложь)
    
    Запрос = Новый Запрос;
    
    ТекстЗапроса = 
    "ВЫБРАТЬ ПЕРВЫЕ 1
    |	Папки.Ссылка КАК Ссылка
    |ИЗ
    |	Справочник.ПапкиВнутреннихДокументов КАК Папки
    |ГДЕ
    |	НЕ Папки.ПометкаУдаления
    |	И Папки.Наименование = &Наименование";
    
    Если ИскатьВоВсехВложенных Тогда
        ТекстЗапроса = ТекстЗапроса + " И Папки.Родитель В ИЕРАРХИИ(&Родитель)";
    Иначе
        ТекстЗапроса = ТекстЗапроса + " И Папки.Родитель = &Родитель";
    КонецЕсли;
    
    Запрос.Текст = ТекстЗапроса;
    Запрос.УстановитьПараметр("Наименование", СокрЛП(ИмяПодпапки));
    Запрос.УстановитьПараметр("Родитель", РодительскаяПапка);
    
    Результат = Запрос.Выполнить();
    
    Если Не Результат.Пустой() Тогда
        Выборка = Результат.Выбрать();
        Выборка.Следующий();
        Возврат Выборка.Ссылка;
    КонецЕсли;
    
    Возврат Справочники.ПапкиВнутреннихДокументов.ПустаяСсылка();
    
КонецФункции

Важные практические нюансы

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

  1. Права доступа на уровне записей (RLS): в «1С:Документооборот» активно используются политики доступа к папкам. Если текущему пользователю не назначены права на чтение конкретной дочерней папки, она не будет возвращена ни выборкой, ни запросом. Если перебор выполняется в фоновом задании или системном алгоритме, используйте метод УстановитьПривилегированныйРежим(Истина).
  2. Помеченные на удаление объекты: метод ВыбратьИерархически() всегда возвращает удаленные элементы. Если не проверять признак ПометкаУдаления, алгоритм может сопоставить данные со старой удаленной папкой-дублем.
  3. Невидимые символы: при чтении наименований из табличных частей или внешних файлов (Excel, CSV) строки могут содержать неразрывные пробелы (Символы.НПП) или пробелы на концах. Всегда оборачивайте сравниваемые переменные в СокрЛП() и при необходимости очищайте их от спецсимволов.
← На главную