Как загрузить файл Excel в таблицу значений на управляемой форме

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

Загрузка данных из внешних файлов Excel в информационную базу — одна из самых частых задач, с которыми сталкивается разработчик 1С. Однако при работе с управляемыми формами начинающие специалисты часто натыкаются на специфическую ошибку: "Нельзя изменять поле, содержащее объект данных формы". В этой статье мы подробно разберем, почему возникает эта ситуация, и рассмотрим несколько эффективных способов реализации загрузки данных.

Почему возникает ошибка при попытке присвоить таблицу значений?

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

БазовыеЦены = ПЗ.Результат.Выгрузить();

Здесь БазовыеЦены — это реквизит управляемой формы с типом СписокЗначений или ДанныеФормыКоллекция (таблица). Ошибка возникает потому, что в управляемом приложении объекты на форме (в памяти клиента) и объекты базы данных (в памяти сервера) имеют разные типы. Метод Выгрузить() возвращает объект типа ТаблицаЗначений, который является чисто серверным объектом. Реквизит же формы на самом деле является объектом типа ДанныеФормыКоллекция. Прямое присваивание между ними запрещено платформой.

Способ 1. Построчный обход данных (универсальный метод)

Самый простой и понятный способ — это перебор строк загруженной таблицы и добавление их в таблицу на форме по одной. Рассмотрим, как это реализовать. Предположим, мы уже прочитали файл Excel во временную таблицу значений тз_.

Разберем программный код для заполнения таблицы на форме:


// Предположим, тз_ - это ТаблицаЗначений, полученная из Excel
Для каждого СтрокаИзExcel Из тз_ Цикл
    // Добавляем новую строку в таблицу на форме (БазовыеЦены)
    НоваяСтрокаФормы = БазовыеЦены.Добавить();
    
    // Копируем значения всех колонок, имена которых совпадают
    ЗаполнитьЗначенияСвойств(НоваяСтрокаФормы, СтрокаИзExcel);
КонецЦикла;

Этот метод хорош тем, что он работает как на клиенте, так и на сервере. Однако при очень больших объемах данных (десятки тысяч строк) такая загрузка может выполняться медленно.

Способ 2. Использование метода ЗначениеВРеквизитФормы (высокая производительность)

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

Рассмотрим алгоритм действий:

  1. Создаем на сервере объект ТаблицаЗначений.
  2. Заполняем её данными из Excel.
  3. Используем метод ЗначениеВРеквизитФормы() для мгновенного обновления интерфейса.

Пример серверного кода:


&НаСервере
Процедура ЗагрузитьДанныеНаСервере(АдресХранилища)
    // 1. Получаем таблицу значений из данных Excel
    // (Логика чтения файла здесь опущена для краткости)
    ТаблицаОбъект = ПолучитьТаблицуИзExcel(АдресХранилища);
    
    // 2. "Закидываем" всю таблицу целиком в реквизит формы
    // "БазовыеЦены" - это имя реквизита на форме в виде строки
    ЗначениеВРеквизитФормы(ТаблицаОбъект, "БазовыеЦены");
КонецПроцедуры

Способ 3. Передача файла с клиента на сервер через временное хранилище

Часто возникает вопрос: как сервер "увидит" файл, который лежит на рабочем столе пользователя? В управляемом приложении сервер не имеет прямого доступа к локальным дискам клиента. Поэтому мы должны сначала передать файл в специальное "облако" — временное хранилище.

Разберем по шагам правильный механизм выбора и передачи файла:


&НаКлиенте
Процедура ВыбратьФайлИЗагрузить()
    Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
    Диалог.Фильтр = "Excel (*.xlsx)|*.xlsx";
    
    Если Диалог.Выбрать() Тогда
        // Помещаем файл во временное хранилище
        ОписаниеФайла = Новый ОписаниеПередаваемогоФайла(Диалог.ПолноеИмяФайла);
        ПередаваемыеФайлы = Новый Массив;
        ПередаваемыеФайлы.Добавить(ОписаниеФайла);
        
        // Эта функция возвращает адрес в хранилище
        АдресХранилища = "";
        РезультатПередачи = ПоместитьФайлы(,, ПередаваемыеФайлы, Ложь, ЭтаФорма.УникальныйИдентификатор);
        
        Если РезультатПередачи Тогда
             АдресХранилища = ПередаваемыеФайлы[0].Хранение;
             // Вызываем серверную процедуру для обработки
             ЗагрузитьДанныеНаСервере(АдресХранилища);
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Современные возможности: Чтение Excel без установленного Microsoft Office

Важный нюанс, который прозвучал в обсуждении: современные версии платформы 1С (начиная с 8.3.6) позволяют читать файлы .xlsx напрямую с помощью объекта ТабличныйДокумент. Это избавляет от необходимости устанавливать Excel на сервере, что особенно актуально для Linux-серверов.

Проанализируем пример кода для чтения файла через ТабличныйДокумент:


&НаСервере
Функция ПрочитатьExcelЧерезТабДок(АдресХранилища)
    ТабДок = Новый ТабличныйДокумент;
    // Получаем данные из хранилища
    ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресХранилища);
    Поток = Новый ПотокВПамяти(ДвоичныеДанные);
    
    // Читаем напрямую в формате XLSX
    ТабДок.Прочитать(Поток, СпособЧтенияЗначенийТабличногоДокумента.Значение);
    
    // Теперь можно использовать ПостроительЗапроса или просто обход областей
    // для извлечения данных в Таблицу Значений
    // ...
КонецФункции

Рекомендации по типам данных

При загрузке из Excel часто возникают проблемы с типами: например, артикул "00123" может прочитаться как число 123, и ведущие нули пропадут. Чтобы избежать этого, при создании временной таблицы значений всегда явно указывайте ОписаниеТипов для каждой колонки.

Посмотрим на пример правильной инициализации таблицы:


КЧ = Новый КвалификаторыЧисла(15, 2);
КС = Новый КвалификаторыСтроки(100);
МассивТипаЧисло = Новый Массив; МассивТипаЧисло.Добавить(Тип("Число"));
МассивТипаСтрока = Новый Массив; МассивТипаСтрока.Добавить(Тип("Строка"));

ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Наименование", Новый ОписаниеТипов(МассивТипаСтрока, , КС));
ТЗ.Колонки.Добавить("Цена", Новый ОписаниеТипов(МассивТипаЧисло, КЧ));

Резюме: Чтобы загрузить Excel в таблицу на форме без ошибок, используйте построчный обход с ЗаполнитьЗначенияСвойств или метод ЗначениеВРеквизитФормы на сервере. Всегда передавайте файл через временное хранилище и старайтесь использовать нативный метод Прочитать объекта ТабличныйДокумент для обеспечения стабильной работы системы.

← На главную