Как получить список листов Excel на сервере и передать его для выбора на клиенте

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

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

Постановка задачи и архитектурный подход

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

Способ 1. Использование серверной функции и события «НачалоВыбора»

Проанализируем наиболее гибкий вариант, когда список листов запрашивается в момент обращения пользователя к элементу формы. Для этого мы будем использовать событие НачалоВыбора. Главный секрет здесь заключается в параметре СтандартнаяОбработка, который нужно установить в значение Ложь, чтобы подавить стандартное окно выбора и подставить свои данные.

Разберем пример кода для клиентской и серверной части:


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

КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьСписокЛистовНаСервере(Знач ПутьКФайлу)
    
    Список = Новый СписокЗначений;
    
    Попытка
        Excel = Новый COMОбъект("Excel.Application");
        Книга = Excel.WorkBooks.Open(ПутьКФайлу);
        
        Для Каждого ТекущийЛист Из Книга.WorkSheets Цикл
            Список.Добавить(ТекущийЛист.Name);
        КонецЦикла;
        
        Книга.Close(Ложь);
        Excel.Quit();
    Исключение
        // Важно закрыть процесс Excel в случае ошибки
        Если Excel <> Неопределено Тогда
            Excel.Quit();
        КонецЕсли;
        Сообщить("Ошибка при чтении файла: " + ОписаниеОшибки());
    КонецПопытки;
    
    Возврат Список;

КонецФункции

В данном примере мы использовали директиву &НаСервереБезКонтекста. Это лучшая практика, так как такая функция работает быстрее, не передавая все данные формы на сервер и обратно. Мы передаем только путь к файлу и получаем готовый СписокЗначений.

Способ 2. Использование реквизита формы для хранения списка

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

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

  1. Создайте в редакторе формы реквизит, например, ДоступныеЛисты с типом СписокЗначений.
  2. В процедуре, которая выполняется при изменении пути к файлу, заполните этот реквизит на сервере.
  3. Настройте элемент формы (поле выбора), указав в свойстве СписокВыбора этот реквизит.

Это позволит избежать повторных и тяжелых вызовов COM-объекта при каждом клике пользователя, так как данные уже будут находиться в контексте формы на стороне клиента.

Проблема «Магических чисел» и выбор конкретного листа

Часто начинающие программисты используют жесткую привязку к номеру листа, например Лист = Книга.WorkSheets(2). Проанализируем ситуацию: если пользователь выберет в списке «Лист 3», а в коде прописано число 2, загрузка пройдет некорректно. Чтобы этого избежать, нужно передавать в процедуру обработки не индекс, а имя листа, полученное из списка выбора.

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


// В процедуре обработки на сервере
ЛистДляЗагрузки = Книга.WorkSheets(ВыбранноеИмяЛиста);
// Теперь объект 'ЛистДляЗагрузки' указывает именно на тот лист, который выбрал пользователь

Оптимизация: Как избежать использования COM на сервере

Работа с COMОбъект("Excel.Application") на сервере сопряжена с рисками: процесс может «зависнуть», потребляя память, или Excel может быть вовсе не установлен на серверной ОС (особенно если это Linux). Рассмотрим более надежный и современный метод — использование встроенного объекта ТабличныйДокумент.

Начиная с версии 8.3.6, 1С умеет нативно читать файлы XLSX. Хотя ТабличныйДокумент не предоставляет прямой список имен листов так же просто, как COM, он работает значительно стабильнее. Если же вам критически важно получить именно структуру книги без установки Office, рекомендуем обратить внимание на ADO (ActiveX Data Objects) или чтение XLSX как ZIP-архива с последующим разбором workbook.xml.

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


&НаСервере
Процедура ПрочитатьФайлНативно(Путь)
    ТабДок = Новый ТабличныйДокумент;
    Попытка
        ТабДок.Прочитать(Путь, СпособЧтенияТабличногоДокумента.XLSX);
        // Далее работаем с ТабДок как с обычной таблицей 1С
    Исключение
        Сообщить("Файл не прочитан");
    КонецПопытки;
КонецПроцедуры

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

При работе в клиент-серверном варианте всегда помните о следующих моментах:

Таким образом, мы разобрали основной паттерн взаимодействия: получение списка через серверную функцию-контейнер и передачу его в ДанныеВыбора на клиенте. Этот подход является стандартным для платформы 1С:Предприятие 8.3 и обеспечивает отзывчивость интерфейса при работе с внешними данными.

← На главную