Как элегантно преобразовать массив файлов в таблицу значений в 1С

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

При разработке механизмов импорта, экспорта или пакетной обработки файлов на платформе 1С:Предприятие разработчики часто сталкиваются с необходимостью вывести список найденных файлов на форму или обработать их в виде таблицы. Системная функция НайтиФайлы() возвращает массив объектов типа Файл. Напрямую привязать массив к элементу формы типа "Таблица" нельзя — для этого требуется преобразовать полученные данные в ТаблицуЗначений.

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

Анализ исходного решения и его недостатков

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


&НаСервере
Процедура Массив2ТЗ()
    МассивФайлов = НайтиФайлы(Объект.ПутьККаталогу, "*");
    ТЗ = Новый ТаблицаЗначений;
    
    // Ручное добавление каждой колонки
    ТЗ.Колонки.Добавить("Имя", Новый ОписаниеТипов("Строка"));
    ТЗ.Колонки.Добавить("ПолноеИмя", Новый ОписаниеТипов("Строка"));
    ТЗ.Колонки.Добавить("Путь", Новый ОписаниеТипов("Строка"));
    ТЗ.Колонки.Добавить("ИмяБезРасширения", Новый ОписаниеТипов("Строка"));
    ТЗ.Колонки.Добавить("Расширение", Новый ОписаниеТипов("Строка"));
    
    // Ручной перебор и заполнение каждой строки
    Для Каждого стрМас Из МассивФайлов Цикл
        СтрТЗ = ТЗ.Добавить();
        СтрТЗ.Имя = стрМас.Имя;
        СтрТЗ.ПолноеИмя = стрМас.ПолноеИмя;
        СтрТЗ.Путь = стрМас.Путь;
        СтрТЗ.ИмяБезРасширения = стрМас.ИмяБезРасширения;
        СтрТЗ.Расширение = стрМас.Расширение;
    КонецЦикла;
    
    ЗначениеВРеквизитФормы(ТЗ, "ТЗформ");
КонецПроцедуры

Этот код абсолютно рабочий, но у него есть несколько существенных недостатков:

  1. Избыточность (раздувание кода): Нам приходится дублировать имена свойств объекта Файл сначала при объявлении колонок таблицы значений, а затем при заполнении каждой строки. Если свойств будет больше (например, размер файла или дата его изменения), код увеличится в геометрической прогрессии.
  2. Плохая масштабируемость: При необходимости добавить новое свойство в таблицу придется вносить изменения в несколько мест программы.

Оптимизация с использованием ЗаполнитьЗначенияСвойств

Для сокращения кода заполнения строк логично использовать встроенную процедуру платформы ЗаполнитьЗначенияСвойств(). Она автоматически сопоставляет имена колонок в приемнике с именами свойств в источнике и копирует данные.

Однако здесь программистов часто подстерегает ошибка. Попытка написать код в таком виде:


Для Каждого стрМас Из МассивФайлов Цикл
    ЗаполнитьЗначенияСвойств(ТЗ.Добавить(), стрМас);
КонецЦикла;

приведет к ошибке "Поле объекта не обнаружено..." при последующих обращениях к колонкам или просто оставит таблицу пустой. Выясним причину этой проблемы.

Важное правило платформы 1С: метод ЗаполнитьЗначенияСвойств() работает только с теми колонками таблицы-приемника, которые уже существуют на момент вызова. Он не создает колонки в ТаблицеЗначений динамически. Соответственно, перед заполнением структуры данных колонки обязательно должны быть добавлены в ТЗ.

Элегантный способ создания колонок и заполнения данных

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


&НаСервере
Процедура БыстроеЗаполнениеТЗ()
    МассивФайлов = НайтиФайлы(Объект.ПутьККаталогу, "*");
    ТЗ = Новый ТаблицаЗначений;
    
    // 1. Быстрое создание колонок из строки свойств
    СписокСвойств = "Имя,ПолноеИмя,Путь,ИмяБезРасширения,Расширение,Размер";
    Для Каждого ИмяКолонки Из СтрРазделить(СписокСвойств, ",") Цикл
        ТЗ.Колонки.Добавить(ИмяКолонки); 
    КонецЦикла;
    
    // 2. Наполнение таблицы в 3 строки кода
    Для Каждого ОбъектФайл Из МассивФайлов Цикл
        ЗаполнитьЗначенияСвойств(ТЗ.Добавить(), ОбъектФайл);
    КонецЦикла;
    
    ЗначениеВРеквизитФормы(ТЗ, "ТЗформ");
КонецПроцедуры

Этот вариант невероятно лаконичен. Если нам понадобится добавить новые свойства файла (например, ПолучитьВремяИзменения()), достаточно будет просто дописать имя нового свойства в строковую переменную СписокСвойств.

Почему нельзя автоматически получить свойства первого элемента МассивФайлов[0]?

У некоторых разработчиков возникает идея: "А почему бы не проанализировать первый элемент массива программно, перебрать его свойства в цикле и на их основе создать колонки?".

Проанализируем эту ситуацию. В 1С такой подход сработает, если бы элементами массива были объекты типа Структура или Соответствие. Мы могли бы сделать так:


// Это работает только для структур!
Для Каждого КлючИЗначение Из МассивСтруктур[0] Цикл
    ТЗ.Колонки.Добавить(КлючИЗначение.Ключ);
КонецЦикла;

Однако для системного типа данных Файл такой подход невозможен. Платформа 1С:Предприятие не предоставляет механизмов динамической рефлексии метаданных для примитивных и прикладных объектных типов. У объекта типа Файл нет коллекции свойств, доступной для программного обхода циклом Для Каждого. Единственный способ прочитать его свойства — обратиться к ним напрямую по известному заранее имени.

Универсальный метод конвертации для "Массива структур"

В современной практике разработки на управляемых формах очень часто применяется паттерн передачи табличных данных между сервером и клиентом в виде Массива Структур. Саму ТаблицуЗначений нельзя передать на клиентскую сторону без помещения во временное хранилище или конвертации.

Если вы предварительно перевели файлы в массив структур, вы можете использовать полностью универсальную функцию создания ТЗ:


&НаСервереБезКонтекста
Функция ПреобразоватьМассивСтруктурВТЗ(МассивСтруктур)
    ТЗ = Новый ТаблицаЗначений;
    
    Если МассивСтруктур.Количество() = 0 Тогда
        Возврат ТЗ;
    КонецЕсли;
    
    // Динамически создаем колонки по ключам первой структуры
    Для Каждого Свойство Из МассивСтруктур[0] Цикл
        ТЗ.Колонки.Добавить(Свойство.Ключ);
    КонецЦикла;
    
    // Быстро заполняем ТЗ
    Для Каждого СтрокаМассива Из МассивСтруктур Цикл
        ЗаполнитьЗначенияСвойств(ТЗ.Добавить(), СтрокаМассива);
    КонецЦикла;
    
    Возврат ТЗ;
КонецФункции

Использование инструментов БСП (Библиотеки стандартных подсистем)

Если ваша конфигурация разработана на основе БСП, вам не обязательно писать собственные велосипеды для конвертации данных. В библиотеке уже содержатся готовые оптимизированные методы общего назначения.

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


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

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

МассивДляКлиента = ОбщегоНазначения.ТаблицаЗначенийВМассив(ТЗ);

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

← На главную