В процессе разработки на платформе 1С:Предприятие 8.3 часто возникает задача: программно сформировать XML-документ и предоставить пользователю возможность сохранить его на локальный диск. В управляемых формах, особенно в современных конфигурациях (таких как БП 3.0, ЗУП 3.1 или ERP), задача осложняется тем, что использование модальных окон запрещено, а работа с файловой системой на стороне клиента имеет свои особенности. Рассмотрим подробнее, как реализовать этот функционал правильно и эффективно.
Самый распространенный способ — это использование стандартного объекта ДиалогВыбораФайла. Поскольку в управляемом приложении мы не можем использовать метод Выбрать(), который блокирует работу интерфейса, мы воспользуемся методом Показать(). Разберем по шагам, как это работает.
Сначала нам нужно создать описание оповещения — специальный объект, который укажет системе, какую процедуру выполнить после того, как пользователь выберет путь к файлу или нажмет «Отмена».
&НаКлиенте
Процедура ФормированиеXML(Команда)
// Получаем строку XML (предположим, она формируется на сервере)
СтрокаXML = СформироватьXMLФайлНаСервере();
// Создаем диалог
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Сохранение);
Диалог.Заголовок = "Выберите путь для сохранения файла XML";
Диалог.ПолноеИмяФайла = "Данные.xml";
Диалог.Фильтр = "Файлы XML (*.xml)|*.xml";
// Описываем процедуру, которая выполнится после закрытия диалога
Оповещение = Новый ОписаниеОповещения("ЗавершитьСохранениеФайла", ЭтотОбъект, СтрокаXML);
// Открываем диалог
Диалог.Показать(Оповещение);
КонецПроцедуры
&НаКлиенте
Процедура ЗавершитьСохранениеФайла(ВыбранныеФайлы, ДополнительныеПараметры) Экспорт
Если ВыбранныеФайлы = Неопределено Тогда
Возврат; // Пользователь отказался от выбора
КонецЕсли;
ПутьКФайлу = ВыбранныеФайлы[0];
СтрокаXML = ДополнительныеПараметры;
// Записываем текст в файл
Текст = Новый ТекстовыйДокумент;
Текст.УстановитьТекст(СтрокаXML);
Попытка
Текст.Записать(ПутьКФайлу, КодировкаТекста.UTF8);
Сообщить("Файл успешно сохранен: " + ПутьКФайлу);
Исключение
Предупреждение("Ошибка при записи файла: " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Проанализируем этот код: мы передаем СтрокаXML в качестве третьего параметра в ОписаниеОповещения. Это позволяет нам "пробросить" данные из основной процедуры в процедуру завершения, не создавая лишних реквизитов формы.
Использование ТекстовыйДокумент иногда может приводить к проблемам с кодировкой (например, автоматическое добавление BOM-метки в UTF-8), что критично для некоторых государственных сервисов. Более надежный способ — преобразовать строку в ДвоичныеДанные. Выясним причину: объект ДвоичныеДанные сохраняет информацию байт-в-байт.
Рассмотрим пример, где файл сначала формируется во временном хранилище на сервере, а затем скачивается клиентом. Это "золотой стандарт" для веб-клиентов и тонких клиентов.
&НаКлиенте
Процедура СохранитьXMLЧерезХранилище(Команда)
// Формируем данные на сервере и получаем адрес во временном хранилище
Результат = СформироватьФайлИПоместитьВХранилище();
ПараметрыПолучения = Новый ПараметрыПолученияФайла;
ПараметрыПолучения.Заголовок = "Сохранение XML";
// Метод ПолучитьФайл инициирует стандартную загрузку файла в браузере
// или открывает диалог сохранения в тонком клиенте
ПолучитьФайл(Результат.Адрес, Результат.ИмяФайла, Истина);
КонецПроцедуры
&НаСервере
Функция СформироватьФайлИПоместитьВХранилище()
СтрокаXML = "<?xml version=""1.0"" encoding=""UTF-8""?><root>Данные</root>";
// Преобразуем строку в двоичные данные с явным указанием кодировки
ДвоичныеДанные = ПолучитьДвоичныеДанныеИзСтроки(СтрокаXML, КодировкаТекста.UTF8, Ложь);
ИмяФайла = "export.xml";
Адрес = ПоместитьВоВременноеХранилище(ДвоичныеДанные, Новый УникальныйИдентификатор);
Возврат Новый Структура("Адрес, ИмяФайла", Адрес, ИмяФайла);
КонецФункции
Если вы работаете в современной конфигурации, такой как "1С:Бухгалтерия 3.0", крайне рекомендуем использовать программный интерфейс БСП. Это избавит вас от необходимости вручную прописывать ОписаниеОповещения. Общий модуль ФайловаяСистемаКлиент содержит готовый метод СохранитьФайл().
Посмотрим на пример реализации:
&НаКлиенте
Процедура СохранитьЧерезБСП(Команда)
АдресХранилища = ПодготовитьФайлНаСервере();
ПараметрыСохранения = ФайловаяСистемаКлиент.ПараметрыСохраненияФайла();
ПараметрыСохранения.ИмяФайла = "Отчет.xml";
ПараметрыСохранения.Заголовок = "Куда сохранить XML?";
ФайловаяСистемаКлиент.СохранитьФайл(Неопределено, АдресХранилища, ПараметрыСохранения);
КонецПроцедуры
Этот метод самостоятельно обработает все нюансы: предложит диалог пользователю, проверит права доступа и корректно запишет данные из временного хранилища на диск. Это наиболее "чистый" код с точки зрения поддержки конфигурации.
Разберем ситуацию, когда данных очень много. Вместо того чтобы формировать гигантскую строку в памяти, лучше использовать объект ЗаписьXML. Он позволяет записывать данные порциями (потоково), что значительно экономит оперативную память сервера.
&НаСервере
Функция СформироватьБольшойXML()
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xml");
Запись = Новый ЗаписьXML;
ПараметрыЗаписи = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Ложь); // Ложь - не добавлять BOM
Запись.ОткрытьФайл(ИмяВременногоФайла, ПараметрыЗаписи);
Запись.ЗаписатьОбъявлениеXML();
Запись.ЗаписатьНачалоЭлемента("Данные");
// Цикл по тысячам записей...
Для Каждого Стр Из ТаблицаДанных Цикл
Запись.ЗаписатьНачалоЭлемента("Элемент");
Запись.ЗаписатьТекст(Стр.Значение);
Запись.ЗаписатьКонецЭлемента();
КонецЦикла;
Запись.ЗаписатьКонецЭлемента();
Запись.Закрыть();
ДвоичныеДанные = Новый ДвоичныеДанные(ИмяВременногоФайла);
УдалитьФайлы(ИмяВременногоФайла);
Возврат ПоместитьВоВременноеХранилище(ДвоичныеДанные);
КонецФункции
Важный момент: Обратите внимание на третий параметр в ПараметрыЗаписиXML. Установка его в значение Ложь гарантирует, что в начале файла не будет лишних невидимых символов (Byte Order Mark), которые часто мешают корректному чтению XML сторонними программами.
В последних версиях платформы 1С реализован механизм Ждать (Async/Await), который делает код линейным, несмотря на использование диалогов. Если ваша конфигурация работает на режиме совместимости 8.3.15 и выше, можно использовать ПолучитьФайлыАсинхр.
Проанализируем пример:
&НаКлиенте
Асинхр Процедура СохранитьФайлАсинхронно(Команда)
АдресХранилища = СформироватьФайлНаСервере();
ОписаниеФайла = Новый ОписаниеПередаваемогоФайла("result.xml", АдресХранилища);
МассивФайлов = Новый Массив;
МассивФайлов.Добавить(ОписаниеФайла);
ПараметрыДиалога = Новый ПараметрыДиалогаПолученияФайлов;
// Программа "замрет" на этой строке до выбора файла пользователем,
// но интерфейс останется отзывчивым
Ждать ПолучитьФайлыАсинхр(МассивФайлов, ПараметрыДиалога);
КонецПроцедуры
Использование асинхронных методов — это наиболее современный подход, который избавляет от необходимости плодить множество процедур-оповещений ("ЗавершитьСохранение", "ПослеВыбора" и т.д.) и делает код значительно более читаемым.
Для выбора оптимального способа сохранения XML на диск воспользуйтесь следующими правилами:
ФайловаяСистемаКлиент.СохранитьФайл(). Это самый надежный способ, протестированный вендором.ТекстовыйДокумент с использованием ОписаниеОповещения.ЗаписьXML на сервере, помещайте результат в ДвоичныеДанные и передавайте на клиент через временное хранилище. Это гарантирует правильную кодировку.Таким образом, задача сохранения XML на диск в управляемом приложении решается несколькими способами, каждый из которых подходит под свои задачи. Выбирайте тот, который соответствует архитектуре вашей конфигурации и версии платформы.