Как сохранить сформированный на сервере файл Excel на клиенте в 1С 8.3?

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

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

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

Схема 1. Передача файла Excel через Временное Хранилище и Двоичные Данные

Разберем классическую схему передачи. Файл создается на сервере во временной папке, упаковывается в объект ДвоичныеДанные, затем помещается во временное хранилище. На сторону клиента возвращается только адрес хранилища, по которому данные извлекаются и сохраняются в выбранный пользователем путь.

Рассмотрим реализацию на управляемых формах:


&НаКлиенте
Процедура ВыполнитьВыгрузку(Команда)
    
    // 1. Формируем файл на сервере и получаем адрес во временном хранилище
    АдресХранилища = ПодготовитьФайлExcelНаСервере();
    
    Если Не ЗначениеЗаполнено(АдресХранилища) Тогда
        Возврат;
    КонецЕсли;
    
    // 2. Открываем диалог для выбора пути сохранения на клиенте
    ДиалогСохранения = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Сохранение);
    ДиалогСохранения.ПолноеИмяФайла = "Выгрузка.xls";
    ДиалогСохранения.Фильтр = НСтр("ru = 'Книга Excel (*.xls)|*.xls|Все файлы (*.*)|*.*'");
    ДиалогСохранения.Заголовок = НСтр("ru = 'Выберите путь для сохранения файла'");
    
    Если ДиалогСохранения.Выбрать() Тогда
        ИмяФайлаНаКлиенте = ДиалогСохранения.ПолноеИмяФайла;
        
        // 3. Получаем данные из хранилища и сохраняем на диск
        ДвоичныеДанныеФайла = ПолучитьИзВременногоХранилища(АдресХранилища);
        ДвоичныеДанныеФайла.Записать(ИмяФайлаНаКлиенте);
        
        ПоказатьОповещениеПользователя(
            "Успешно",
            ,
            "Файл успешно сохранен: " + ИмяФайлаНаКлиенте,
            ,
            СтатусОповещенияПользователя.Информация
        );
    КонецЕсли;
    
КонецПроцедуры

&НаСервере
Функция ПодготовитьФайлExcelНаСервере()
    
    // Инициализация COM-объекта Excel
    Excel = Новый COMОбъект("Excel.Application");
    Excel.DisplayAlerts = 0;
    
    Книга = Excel.Workbooks.Add();
    Лист = Книга.Worksheets(1);
    
    // Заполняем данные
    Лист.Cells(1, 1).Value = "Тестовые данные";
    
    ИмяВременногоФайла = ПолучитьИмяВременногоФайла(".xls");
    
    // Сохраняем книгу во временный файл
    Excel.DefaultSaveFormat = 56; // Формат xlExcel8 (xls)
    Книга.SaveCopyAs(ИмяВременногоФайла);
    
    // Обязательно корректно закрываем приложение и очищаем COM-ссылки
    Книга.Close(Ложь);
    Excel.Quit();
    Книга = Неопределено;
    Лист = Неопределено;
    Excel = Неопределено;
    
    // Преобразуем файл в двоичные данные
    ФайлДанных = Новый ДвоичныеДанные(ИмяВременногоФайла);
    
    // Помещаем во временное хранилище с привязкой к форме
    Адрес = ПоместитьВоВременноеХранилище(ФайлДанных, ЭтотОбъект.УникальныйИдентификатор);
    
    // Удаляем временный файл с диска сервера
    УдалитьФайлы(ИмяВременногоФайла);
    
    Возврат Адрес;
    
КонецФункции

Важные нюансы при работе с Временным Хранилищем и COM

Проанализируем распространенные проблемы, из-за которых возникают сбои при сохранении:

  1. Время жизни данных в хранилище (ошибка «ДанныеФайла = Неопределено»): Если при вызове ПоместитьВоВременноеХранилище не передать вторым параметром ЭтотОбъект.УникальныйИдентификатор (или УникальныйИдентификатор формы), данные будут удалены из хранилища сразу после завершения серверного вызова. На клиенте функция ПолучитьИзВременногоХранилища вернет Неопределено.
  2. Ошибка 0x80004002 при создании COM-объекта: Чаще всего возникает из-за несовпадения разрядности службы сервера 1С (64-bit) и Microsoft Office (32-bit), либо из-за отсутствия прав у системного пользователя сервера 1С (например, USR1CV8). Для работы COM-объекта Excel под системной учетной записью в Windows требуется создать специальные каталоги рабочего стола: C:\Windows\System32\config\systemprofile\Desktop и C:\Windows\SysWOW64\config\systemprofile\Desktop, предоставив на них полные права службе 1С.
  3. Зависшие процессы EXCEL.EXE в диспетчере задач: Вызов Excel.Quit() не всегда сразу выгружает процесс из памяти, если в коде 1С остаются живые ссылки на объекты ячеек, листов или книг. Обязательно присваивайте переменным значение Неопределено после завершения работы.
  4. Несовместимость с Linux: COM-технология работает исключительно в операционных системах Windows. Если сервер 1С работает под управлением Linux, создание COMОбъект("Excel.Application") вызовет исключение.

Схема 2. Формирование многостраничного Excel без COM (ПакетТабличныхДокументов)

Если требуется сформировать файл Excel с несколькими листами и гиперссылками, вовсе не обязательно использовать медленный и платформозависимый COM-объект. Штатные механизмы 1С:Предприятия позволяют формировать книги Excel напрямую с помощью объектов ТабличныйДокумент и ПакетТабличныхДокументов.

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


&НаСервере
Функция СформироватьКнигуXLSXБезCOM()
    
    // Создаем пакет табличных документов для объединения в одну книгу
    Пакет = Новый ПакетТабличныхДокументов;
    
    // Формируем первый лист
    ТабДок1 = Новый ТабличныйДокумент;
    ТабДок1.ИмяПараметровПечати = "Лист1";
    ТабДок1.Область("R1C1").Текст = "Отчет по продажам";
    
    // Добавляем кликабельную гиперссылку
    ОбластьСсылки = ТабДок1.Область("R2C1");
    ОбластьСсылки.Текст = "Перейти на сайт";
    ОбластьСсылки.Гиперссылка = Истина;
    ОбластьСсылки.Текст = "https://1c.ru";
    
    // Формируем второй лист
    ТабДок2 = Новый ТабличныйДокумент;
    ТабДок2.ИмяПараметровПечати = "Лист2";
    ТабДок2.Область("R1C1").Текст = "Детализация";
    
    // Добавляем листы в состав пакета
    Пакет.Состав.Добавить(ТабДок1);
    Пакет.Состав.Добавить(ТабДок2);
    
    ИмяВременногоФайла = ПолучитьИмяВременногоФайла(".xlsx");
    
    // Сохраняем пакет как многостраничный XLSX
    Пакет.Записать(ИмяВременногоФайла, ТипФайлаТабличногоДокумента.XLSX);
    
    ДвоичныеДанные = Новый ДвоичныеДанные(ИмяВременногоФайла);
    Адрес = ПоместитьВоВременноеХранилище(ДвоичныеДанные, ЭтотОбъект.УникальныйИдентификатор);
    
    УдалитьФайлы(ИмяВременногоФайла);
    
    Возврат Адрес;
    
КонецФункции

Схема 3. Асинхронное получение файла на клиенте

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

Разберем реализацию асинхронного сохранения:


&НаКлиенте
Процедура СохранитьФайлАсинхронно(Команда)
    
    // Формируем файл на сервере
    АдресХранилища = СформироватьКнигуXLSXБезCOM();
    
    Если Не ЗначениеЗаполнено(АдресХранилища) Тогда
        Возврат;
    КонецЕсли;
    
    // Настройки получения файла
    ПараметрыПолучения = Новый ПараметрыПолученияФайла(Ложь); // Истина - открыть интерактивный диалог сохранения
    
    // Метод скачивает файл из временного хранилища на клиент
    ПолучитьФайлНаКлиенте(
        АдресХранилища,
        "ВыгрузкаОтчета.xlsx",
        ПараметрыПолучения
    );
    
КонецПроцедуры

Такой подход делает выгрузку кроссплатформенной, корректно работающей как в тонком, так и в веб-клиенте без установки офисных пакетов на сервере 1С.

← На главную