Разработка и Конфигурация · 14 мин
1С: как сохранить файл на клиенте
Как в 1С сохранить файл на клиенте: НачатьСохранениеФайла, ПолучитьФайл, диалог выбора файла, работа с расширением и без него. Примеры кода и типичные ошибки.
Задача сохранить файл на клиенте возникает в 1С постоянно: выгрузить отчёт в Excel, сохранить печатную форму, передать пользователю выгрузку в XML или полученное из внешнего сервиса вложение. Проблема в том, что в клиент-серверной архитектуре код часто выполняется на сервере, где нет доступа к диску пользователя, а тонкий и веб-клиент дополнительно ограничивают работу с файловой системой. Поэтому механизм сохранения выбирается в зависимости от того, где сформирован файл и какой клиент используется.
В управляемых формах базовый сценарий выглядит так: данные готовятся на сервере, помещаются во временное хранилище в виде двоичных данных, а затем на клиенте асинхронным методом сохраняются в выбранное пользователем место. Синхронные методы работы с файлами в тонком и веб-клиенте либо недоступны, либо требуют установки расширения работы с файлами, поэтому современный код строится на асинхронных вызовах с описанием оповещения.
Ниже разобраны рабочие способы: сохранение из временного хранилища, интерактивное сохранение с диалогом выбора файла, работа с расширением и без него, сохранение табличного документа и типичные ошибки, из-за которых файл «не сохраняется» или оказывается пустым.
Где формируется файл: сервер или клиент
Первое, что нужно определить, — где физически создаётся содержимое файла. Если данные берутся из базы (запрос, табличный документ, выгрузка), формировать файл нужно в серверной процедуре: на клиенте нет доступа к запросам и большинству прикладных объектов. Результат серверной процедуры — двоичные данные или адрес временного хранилища.
Типовая схема передачи: на сервере вызывается ПоместитьВоВременноеХранилище(ДвоичныеДанные, УникальныйИдентификаторФормы), функция возвращает адрес. Этот адрес передаётся на клиент, где метод НачатьПолучениеФайлов или ПолучитьФайл записывает данные на диск пользователя. Привязка хранилища к уникальному идентификатору формы важна: без неё данные могут быть удалены до того, как клиент успеет их забрать.
Если файл уже существует на клиенте (например, пользователь выбрал его ранее) и нужно просто скопировать или переименовать, сервер не требуется вовсе — достаточно клиентских методов работы с файлами. Но такой сценарий при сохранении результатов учёта встречается редко.
Сохранение файла без диалога: НачатьСохранениеФайла
Если путь на клиенте известен заранее (например, файл сохраняется во временный каталог пользователя для последующей обработки), используется метод НачатьСохранениеФайла. Он асинхронный: первым параметром принимает описание оповещения, которое будет вызвано после завершения операции.
&НаКлиенте
Процедура СохранитьФайл(Команда)
Адрес = ПолучитьАдресФайлаНаСервере();
Оповещение = Новый ОписаниеОповещения("ПослеСохраненияФайла", ЭтотОбъект);
ИмяФайла = ПолучитьИмяВременногоФайла("xlsx");
НачатьСохранениеФайла(Оповещение, Адрес, ИмяФайла, Ложь);
КонецПроцедуры
&НаКлиенте
Процедура ПослеСохраненияФайла(Результат, ДополнительныеПараметры) Экспорт
Если Результат <> Неопределено Тогда
ПоказатьОповещениеПользователя("Файл сохранён");
КонецЕсли;
КонецПроцедуры
&НаСервере
Функция ПолучитьАдресФайлаНаСервере()
ТабДок = СформироватьТабличныйДокумент();
ИмяВременного = ПолучитьИмяВременногоФайла("xlsx");
ТабДок.Записать(ИмяВременного, ТипФайлаТабличногоДокумента.XLSX);
ДвоичныеДанные = Новый ДвоичныеДанные(ИмяВременного);
УдалитьФайлы(ИмяВременного);
Возврат ПоместитьВоВременноеХранилище(ДвоичныеДанные, УникальныйИдентификатор);
КонецФункции
Четвёртый параметр НачатьСохранениеФайла — признак интерактивности. Если передать Истина, платформа покажет стандартный диалог сохранения; если Ложь — файл будет записан по указанному пути молча. Обратите внимание: в веб-клиенте «молчаливое» сохранение по произвольному пути невозможно, браузер сам определяет каталог загрузок.
Сохранение с диалогом выбора: ДиалогСохраненияФайла и НачатьПолучениеФайлов
Когда пользователь должен сам выбрать папку и имя, применяется связка ДиалогСохраненияФайла и НачатьПолучениеФайлов. Сначала диалог асинхронно запрашивает путь, затем файл из хранилища записывается по выбранному пути.
&НаКлиенте
Процедура СохранитьСДиалогом(Команда)
Адрес = ПолучитьАдресФайлаНаСервере();
Диалог = Новый ДиалогСохраненияФайла(РежимДиалогаВыбораФайла.Сохранение);
Диалог.Фильтр = "Файл Excel (.xlsx)|.xlsx";
Диалог.ИмяФайла = "Отчёт.xlsx";
Оповещение = Новый ОписаниеОповещения("ПослеВыбораИмени", ЭтотОбъект, Адрес);
Диалог.Показать(Оповещение);
КонецПроцедуры
&НаКлиенте
Процедура ПослеВыбораИмени(ВыбранныеФайлы, Адрес) Экспорт
Если ВыбранныеФайлы = Неопределено Тогда
Возврат;
КонецЕсли;
Передаваемые = Новый Массив;
Передаваемые.Добавить(Новый ОписаниеПередаваемогоФайла(ВыбранныеФайлы[0], Адрес));
НачатьПолучениеФайлов(Новый ОписаниеОповещения("ПослеПолучения", ЭтотОбъект),
Передаваемые, ВыбранныеФайлы[0], Ложь);
КонецПроцедуры
Такой вариант работает и в тонком, и в толстом клиенте. В веб-клиенте диалог выбора пути на диске недоступен — браузер покажет собственное окно загрузки, поэтому там достаточно вызвать ПолучитьФайл(Адрес, ИмяФайла, Истина), и платформа сама инициирует скачивание.
- 1Сформируйте данные на сервере и поместите двоичные данные во временное хранилище с привязкой к форме
- 2Верните адрес хранилища на клиент
- 3Откройте ДиалогСохраненияФайла через метод Показать с описанием оповещения
- 4В обработчике оповещения создайте ОписаниеПередаваемогоФайла и вызовите НачатьПолучениеФайлов
- 5В финальном оповещении проверьте результат и сообщите пользователю об успехе или ошибке
Роль расширения работы с файлами
Расширение работы с файлами — компонент платформы, который устанавливается в браузере и в тонком клиенте и даёт доступ к локальной файловой системе: выбор каталогов, чтение и запись файлов по произвольному пути, получение списка файлов. Без расширения в веб-клиенте доступна только загрузка и скачивание через стандартные механизмы браузера.
Проверить наличие расширения и предложить установку можно так:
&НаКлиенте
Процедура ПроверитьРасширение(Команда)
Оповещение = Новый ОписаниеОповещения("ПослеПроверкиРасширения", ЭтотОбъект);
НачатьПодключениеРасширенияРаботыСФайлами(Оповещение);
КонецПроцедуры
&НаКлиенте
Процедура ПослеПроверкиРасширения(Подключено, ДополнительныеПараметры) Экспорт
Если Не Подключено Тогда
НачатьУстановкуРасширенияРаботыСФайлами();
КонецЕсли;
КонецПроцедуры
Проектируя решение, не делайте расширение обязательным без необходимости: для простого сохранения одного файла достаточно ПолучитьФайл с интерактивным режимом. Расширение оправдано, когда нужно сохранять файлы в заранее заданную папку без диалога, работать с несколькими файлами или читать каталоги пользователя.
Сравнение способов сохранения
Универсальный способ из временного хранилища. Работает в тонком, толстом и веб-клиенте. В веб-клиенте инициирует загрузку через браузер.
Сохранение из хранилища по заданному пути, с диалогом или без. Требует известного пути на клиенте; в веб-клиенте путь ограничен браузером.
Пользователь сам выбирает папку и имя. Не работает в веб-клиенте — там используется штатное скачивание.
Подходит для толстого клиента и тонкого с расширением. В управляемом приложении требует осторожности с директивами компиляции.
Сохранение табличного документа и текстовых файлов
Частный, но очень распространённый случай — сохранить сформированный табличный документ (печатную форму, отчёт) в Excel или PDF. Удобнее всего записать его на сервере во временный файл, получить двоичные данные и дальше действовать по общей схеме с хранилищем. Альтернатива — передать сам табличный документ на клиент (он сериализуется) и записать его уже там методом Записать, но это требует расширения работы с файлами в тонком клиенте.
Для текстовых данных (выгрузки в CSV, XML, JSON) на сервере можно сразу сформировать строку и получить двоичные данные без промежуточного файла: ПолучитьДвоичныеДанныеИзСтроки(Текст, КодировкаТекста.UTF8). Это быстрее и не оставляет временных файлов на сервере — не забудьте только указать правильную кодировку, иначе кириллица в CSV «поедет» при открытии в Excel.
Если требуется открыть сохранённый файл сразу после записи, используйте НачатьЗапускПриложения с путём к файлу или ПерейтиПоНавигационнойСсылке для веб-клиента. Предварительно убедитесь, что операция сохранения завершена — запуск выполняйте только в обработчике оповещения о завершении получения файла.
Типичные ошибки и как их проверить
Самая частая жалоба — «файл сохраняется пустым». Причины почти всегда одни и те же: данные помещены в хранилище без привязки к форме и удалены до получения; на сервере записан пустой табличный документ из-за ошибки в формировании; либо на клиенте путь указан без расширения, и пользователь открывает не тот файл. Диагностику начинайте с проверки размера двоичных данных на сервере — достаточно вывести ДвоичныеДанные.Размер() в журнал регистрации или сообщение.
Вторая группа ошибок — права доступа. Сохранение в системные каталоги (Program Files, корень диска C) у обычного пользователя завершится отказом. Сохраняйте в профиль пользователя: каталог документов, рабочий стол или временный каталог, полученный через ПолучитьИмяВременногоФайла на клиенте. В терминальных сессиях учитывайте, что «диск C» — это диск сервера терминалов, а не компьютера пользователя.
Третья группа — рассинхронизация ожиданий по клиенту. Код, отлаженный в толстом клиенте, падает в тонком или веб-клиенте из-за недоступных методов. Проверяйте решение во всех используемых типах клиентов и обрамляйте специфичные ветки директивами #Если ТолстыйКлиентОбычноеПриложение Тогда или проверкой ЭтоВебКлиент через ПолучитьИнформациюЭкрановКлиента либо структуру системной информации.
Как проверить результат
Размер больше нуля и соответствует содержимому
Размер нулевой — ошибка на этапе формирования данных
Файл существует, открывается целевой программой без предупреждений
Файл нулевого размера или программа сообщает о повреждении
Оповещение вызывается, параметр результата не Неопределено
Оповещение не вызывается — прервана цепочка асинхронных вызовов
Сохранение работает в тонком и веб-клиенте
Работает только в толстом клиенте — использованы недоступные методы
Частые вопросы
Как сохранить файл на клиенте в веб-клиенте без расширения?
Вызовите на клиенте ПолучитьФайл(АдресХранилища, ИмяФайла, Истина). Платформа передаст файл браузеру, и тот выполнит стандартную загрузку в папку скачиваний. Выбрать произвольный каталог на диске без расширения работы с файлами в веб-клиенте нельзя — это ограничение браузерной модели безопасности.
Чем НачатьПолучениеФайлов отличается от НачатьСохранениеФайла?
НачатьПолучениеФайлов работает с массивом описаний передаваемых файлов и предназначен именно для передачи данных из хранилища на клиент, в том числе нескольких файлов за один вызов. НачатьСохранениеФайла сохраняет один файл из хранилища по указанному пути и умеет показывать диалог. Для одиночного файла с выбором пути удобнее второй, для пакетной передачи — первый.
Почему файл сохраняется, но не открывается в Excel?
Чаще всего несовпадение реального формата и расширения: табличный документ записан в формате MXL, а имя файла указано с расширением xlsx. Записывайте документ с явным типом, например ТабДок.Записать(Имя, ТипФайлаТабличногоДокумента.XLSX), и давайте файлу соответствующее расширение. Также проверьте, что в хранилище попали именно двоичные данные файла, а не строка с путём к нему на сервере.
Можно ли сохранить файл на клиенте полностью без серверного вызова?
Да, если содержимое формируется на клиенте: например, текст собирается из полей формы. Создайте ТекстовыйДокумент или получите двоичные данные из строки и запишите их, но в тонком и веб-клиенте для записи по произвольному пути потребуется расширение работы с файлами. Данные из базы без обращения к серверу получить нельзя.
Как сохранить сразу несколько файлов одним действием?
Сформируйте на сервере массив адресов временного хранилища (или один архив ZIP), передайте на клиент и вызовите НачатьПолучениеФайлов с массивом объектов ОписаниеПередаваемогоФайла. Если файлов много, надёжнее упаковать их в архив на сервере — пользователю проще получить один файл, а цепочка вызовов сокращается до одного скачивания.
Где безопасно сохранять файл, чтобы не было ошибок доступа?
В каталоги профиля пользователя: «Документы», «Рабочий стол», временный каталог. Избегайте системных папок и корня системного диска. В терминальной среде помните, что локальные диски в коде — это диски сервера, а не устройства пользователя; для передачи файла именно на компьютер пользователя используйте механизмы передачи файлов платформы, а не прямую запись по пути.
Что важно запомнить
Базовая схема одна: данные формируются на сервере, помещаются во временное хранилище с привязкой к форме, а на клиенте сохраняются асинхронным методом — НачатьСохранениеФайла, ПолучитьФайл или НачатьПолучениеФайлов с диалогом выбора пути. Расширение работы с файлами подключайте только когда нужен произвольный доступ к диску. Проверяйте размер данных на сервере, обрабатывайте отказ пользователя в диалоге и тестируйте код во всех типах клиентов.