В клиент-серверной архитектуре 1С:Предприятия начинающие разработчики часто сталкиваются с ситуацией, когда файл формируется на сервере, а сохранить его необходимо на локальный компьютер пользователя. Попытка просто вернуть строку с путем к временному файлу (полученному через функцию ПолучитьИмяВременногоФайла) на сторону клиента приводит к ошибке, поскольку файловые системы сервера и клиентского компьютера изолированы друг от друга.
Проанализируем основные способы решения этой задачи: стандартную схему передачи файла через временное хранилище, разберем частые ошибки при работе с COM-объектом 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 = Неопределено;
// Преобразуем файл в двоичные данные
ФайлДанных = Новый ДвоичныеДанные(ИмяВременногоФайла);
// Помещаем во временное хранилище с привязкой к форме
Адрес = ПоместитьВоВременноеХранилище(ФайлДанных, ЭтотОбъект.УникальныйИдентификатор);
// Удаляем временный файл с диска сервера
УдалитьФайлы(ИмяВременногоФайла);
Возврат Адрес;
КонецФункции
Проанализируем распространенные проблемы, из-за которых возникают сбои при сохранении:
ПоместитьВоВременноеХранилище не передать вторым параметром ЭтотОбъект.УникальныйИдентификатор (или УникальныйИдентификатор формы), данные будут удалены из хранилища сразу после завершения серверного вызова. На клиенте функция ПолучитьИзВременногоХранилища вернет Неопределено.USR1CV8). Для работы COM-объекта Excel под системной учетной записью в Windows требуется создать специальные каталоги рабочего стола: C:\Windows\System32\config\systemprofile\Desktop и C:\Windows\SysWOW64\config\systemprofile\Desktop, предоставив на них полные права службе 1С.EXCEL.EXE в диспетчере задач: Вызов Excel.Quit() не всегда сразу выгружает процесс из памяти, если в коде 1С остаются живые ссылки на объекты ячеек, листов или книг. Обязательно присваивайте переменным значение Неопределено после завершения работы.COMОбъект("Excel.Application") вызовет исключение.Если требуется сформировать файл 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);
ДвоичныеДанные = Новый ДвоичныеДанные(ИмяВременногоФайла);
Адрес = ПоместитьВоВременноеХранилище(ДвоичныеДанные, ЭтотОбъект.УникальныйИдентификатор);
УдалитьФайлы(ИмяВременногоФайла);
Возврат Адрес;
КонецФункции
В современных конфигурациях с установленным режимом «Запретить синхронные вызовы» синхронный метод ДиалогВыбораФайла.Выбрать() вызывает исключение. Кроме того, этот метод не работает в веб-клиенте. Платформа 1С предоставляет универсальный асинхронный метод ПолучитьФайлНаКлиенте (или ПолучитьФайлы), который берет данные напрямую из временного хранилища и передает их в браузер или на локальный компьютер.
Разберем реализацию асинхронного сохранения:
&НаКлиенте
Процедура СохранитьФайлАсинхронно(Команда)
// Формируем файл на сервере
АдресХранилища = СформироватьКнигуXLSXБезCOM();
Если Не ЗначениеЗаполнено(АдресХранилища) Тогда
Возврат;
КонецЕсли;
// Настройки получения файла
ПараметрыПолучения = Новый ПараметрыПолученияФайла(Ложь); // Истина - открыть интерактивный диалог сохранения
// Метод скачивает файл из временного хранилища на клиент
ПолучитьФайлНаКлиенте(
АдресХранилища,
"ВыгрузкаОтчета.xlsx",
ПараметрыПолучения
);
КонецПроцедуры
Такой подход делает выгрузку кроссплатформенной, корректно работающей как в тонком, так и в веб-клиенте без установки офисных пакетов на сервере 1С.