При разработке механизмов импорта, экспорта или пакетной обработки файлов на платформе 1С:Предприятие разработчики часто сталкиваются с необходимостью вывести список найденных файлов на форму или обработать их в виде таблицы. Системная функция НайтиФайлы() возвращает массив объектов типа Файл. Напрямую привязать массив к элементу формы типа "Таблица" нельзя — для этого требуется преобразовать полученные данные в ТаблицуЗначений.
В этой статье мы подробно разберем, как сделать этот переход красивым, лаконичным и быстрым, избегая рутины с ручным созданием колонок и построчным копированием каждого свойства файла.
Рассмотрим стандартный "лобовой" подход, который часто используют начинающие программисты. Код выглядит следующим образом:
&НаСервере
Процедура Массив2ТЗ()
МассивФайлов = НайтиФайлы(Объект.ПутьККаталогу, "*");
ТЗ = Новый ТаблицаЗначений;
// Ручное добавление каждой колонки
ТЗ.Колонки.Добавить("Имя", Новый ОписаниеТипов("Строка"));
ТЗ.Колонки.Добавить("ПолноеИмя", Новый ОписаниеТипов("Строка"));
ТЗ.Колонки.Добавить("Путь", Новый ОписаниеТипов("Строка"));
ТЗ.Колонки.Добавить("ИмяБезРасширения", Новый ОписаниеТипов("Строка"));
ТЗ.Колонки.Добавить("Расширение", Новый ОписаниеТипов("Строка"));
// Ручной перебор и заполнение каждой строки
Для Каждого стрМас Из МассивФайлов Цикл
СтрТЗ = ТЗ.Добавить();
СтрТЗ.Имя = стрМас.Имя;
СтрТЗ.ПолноеИмя = стрМас.ПолноеИмя;
СтрТЗ.Путь = стрМас.Путь;
СтрТЗ.ИмяБезРасширения = стрМас.ИмяБезРасширения;
СтрТЗ.Расширение = стрМас.Расширение;
КонецЦикла;
ЗначениеВРеквизитФормы(ТЗ, "ТЗформ");
КонецПроцедуры
Этот код абсолютно рабочий, но у него есть несколько существенных недостатков:
Файл сначала при объявлении колонок таблицы значений, а затем при заполнении каждой строки. Если свойств будет больше (например, размер файла или дата его изменения), код увеличится в геометрической прогрессии.Для сокращения кода заполнения строк логично использовать встроенную процедуру платформы ЗаполнитьЗначенияСвойств(). Она автоматически сопоставляет имена колонок в приемнике с именами свойств в источнике и копирует данные.
Однако здесь программистов часто подстерегает ошибка. Попытка написать код в таком виде:
Для Каждого стрМас Из МассивФайлов Цикл
ЗаполнитьЗначенияСвойств(ТЗ.Добавить(), стрМас);
КонецЦикла;
приведет к ошибке "Поле объекта не обнаружено..." при последующих обращениях к колонкам или просто оставит таблицу пустой. Выясним причину этой проблемы.
Важное правило платформы 1С: метод ЗаполнитьЗначенияСвойств() работает только с теми колонками таблицы-приемника, которые уже существуют на момент вызова. Он не создает колонки в ТаблицеЗначений динамически. Соответственно, перед заполнением структуры данных колонки обязательно должны быть добавлены в ТЗ.
Чтобы избежать написания десятка строк с методом ТЗ.Колонки.Добавить(), мы можем упаковать имена необходимых колонок в одну текстовую строку с разделителями, динамически преобразовать ее в массив и добавить колонки в цикле. Посмотрим на готовый элегантный шаблон:
&НаСервере
Процедура БыстроеЗаполнениеТЗ()
МассивФайлов = НайтиФайлы(Объект.ПутьККаталогу, "*");
ТЗ = Новый ТаблицаЗначений;
// 1. Быстрое создание колонок из строки свойств
СписокСвойств = "Имя,ПолноеИмя,Путь,ИмяБезРасширения,Расширение,Размер";
Для Каждого ИмяКолонки Из СтрРазделить(СписокСвойств, ",") Цикл
ТЗ.Колонки.Добавить(ИмяКолонки);
КонецЦикла;
// 2. Наполнение таблицы в 3 строки кода
Для Каждого ОбъектФайл Из МассивФайлов Цикл
ЗаполнитьЗначенияСвойств(ТЗ.Добавить(), ОбъектФайл);
КонецЦикла;
ЗначениеВРеквизитФормы(ТЗ, "ТЗформ");
КонецПроцедуры
Этот вариант невероятно лаконичен. Если нам понадобится добавить новые свойства файла (например, ПолучитьВремяИзменения()), достаточно будет просто дописать имя нового свойства в строковую переменную СписокСвойств.
У некоторых разработчиков возникает идея: "А почему бы не проанализировать первый элемент массива программно, перебрать его свойства в цикле и на их основе создать колонки?".
Проанализируем эту ситуацию. В 1С такой подход сработает, если бы элементами массива были объекты типа Структура или Соответствие. Мы могли бы сделать так:
// Это работает только для структур!
Для Каждого КлючИЗначение Из МассивСтруктур[0] Цикл
ТЗ.Колонки.Добавить(КлючИЗначение.Ключ);
КонецЦикла;
Однако для системного типа данных Файл такой подход невозможен. Платформа 1С:Предприятие не предоставляет механизмов динамической рефлексии метаданных для примитивных и прикладных объектных типов. У объекта типа Файл нет коллекции свойств, доступной для программного обхода циклом Для Каждого. Единственный способ прочитать его свойства — обратиться к ним напрямую по известному заранее имени.
В современной практике разработки на управляемых формах очень часто применяется паттерн передачи табличных данных между сервером и клиентом в виде Массива Структур. Саму ТаблицуЗначений нельзя передать на клиентскую сторону без помещения во временное хранилище или конвертации.
Если вы предварительно перевели файлы в массив структур, вы можете использовать полностью универсальную функцию создания ТЗ:
&НаСервереБезКонтекста
Функция ПреобразоватьМассивСтруктурВТЗ(МассивСтруктур)
ТЗ = Новый ТаблицаЗначений;
Если МассивСтруктур.Количество() = 0 Тогда
Возврат ТЗ;
КонецЕсли;
// Динамически создаем колонки по ключам первой структуры
Для Каждого Свойство Из МассивСтруктур[0] Цикл
ТЗ.Колонки.Добавить(Свойство.Ключ);
КонецЦикла;
// Быстро заполняем ТЗ
Для Каждого СтрокаМассива Из МассивСтруктур Цикл
ЗаполнитьЗначенияСвойств(ТЗ.Добавить(), СтрокаМассива);
КонецЦикла;
Возврат ТЗ;
КонецФункции
Если ваша конфигурация разработана на основе БСП, вам не обязательно писать собственные велосипеды для конвертации данных. В библиотеке уже содержатся готовые оптимизированные методы общего назначения.
Например, если вам нужно дополнить уже существующую и настроенную на форме таблицу значений простым массивом строк (например, путями к файлам), можно использовать готовый метод:
// Заполняет одну колонку ТЗ значениями из одномерного массива
ОбщегоНазначенияКлиентСервер.ДополнитьТаблицуИзМассива(Объект.ТЗформ, МассивПутей, "Путь");
И наоборот, для передачи готовой таблицы на клиентскую сторону в один вызов используйте:
МассивДляКлиента = ОбщегоНазначения.ТаблицаЗначенийВМассив(ТЗ);
Использование комбинации динамического разбора строк с помощью СтрРазделить и метода ЗаполнитьЗначенияСвойств гарантирует чистоту вашего кода, высокую скорость работы и простоту последующей поддержки программного продукта.