При переходе работы пользователей с тонкого клиента на веб-клиент разработчики часто сталкиваются с ошибками при работе с файловой системой. В веб-клиенте браузер из соображений безопасности изолирован от локального диска пользователя, поэтому стандартные вызовы вроде КопироватьФайл() или обращение к файлу по прямому пути типа C:\Users\... вызывают исключения.
Разберем по шагам, как правильно организовать процесс скачивания файла из базы 1С на клиентский компьютер, его открытие во внешнем приложении (например, Microsoft Word) и последующую загрузку отредактированной версии обратно на сервер.
Выясним причину, почему код, работающий в тонком клиенте, не исполняется в браузере:
e1cib/tempstorage/... является лишь внутренним адресом данных в сеансе 1С, а не реальным путем файловой системы Windows или Linux.Перед выполнением любых операций с файловой системой на веб-клиенте необходимо убедиться, что в браузере пользователя установлено и подключено расширение работы с файлами платформы 1С.
Рассмотрим пример проверки и подключения расширения:
#Если ВебКлиент Тогда
Если НЕ ПодключитьРасширениеРаботыСФайлами() Тогда
УстановитьРасширениеРаботыСФайлами();
ПодключитьРасширениеРаботыСФайлами();
КонецЕсли;
#КонецЕсли
Проанализируем процедуру скачивания документа из информационной базы во временную локальную папку пользователя с последующим запуском ассоциированного приложения.
Сначала на сервере получаем двоичные данные файла и помещаем их во временное хранилище, а затем на клиенте вызываем метод ПолучитьФайлы():
&НаСервере
Функция ВернутьАдресХранилища()
ВременныйАдресФайла = "";
Отбор = Новый Структура;
Отбор.Вставить("ВладелецФайла", Объект.БизнесПроцесс.Ссылка);
Отбор.Вставить("ИмяФайла", СокрЛП(Объект.НазваниеИзмененныйДоговор));
КлючЗаписиРег = РегистрыСведений.ФайлыДоговоров.Получить(Объект.ДатаИзмененияДоговора, Отбор);
ДвоичныеДанные = КлючЗаписиРег.ДвоичныеДанныеФайла.Получить();
ВременныйАдресФайла = ПоместитьВоВременноеХранилище(ДвоичныеДанные, УникальныйИдентификатор);
Возврат ВременныйАдресФайла;
КонецФункции
&НаКлиенте
Процедура КнопкаРедактировать(Команда)
#Если ВебКлиент Тогда
Если НЕ ПодключитьРасширениеРаботыСФайлами() Тогда
УстановитьРасширениеРаботыСФайлами();
ПодключитьРасширениеРаботыСФайлами();
КонецЕсли;
#КонецЕсли
ЛокальныйПутьКФайлу = ОбщиеФункцииКлиент.ВернутьПутьКФайлу(Объект.Номер, Объект.НазваниеИзмененныйДоговор);
Если ОбщиеФункцииКлиент.КаталогСуществует(ЛокальныйПутьКФайлу) Тогда
Попытка
ЗапуститьПриложение(ЛокальныйПутьКФайлу);
Исключение
Сообщить(ОписаниеОшибки());
КонецПопытки;
Иначе
Попытка
ВременныйАдрес = ВернутьАдресХранилища();
ПолучаемыйФайл = Новый ОписаниеПередаваемогоФайла(ЛокальныйПутьКФайлу, ВременныйАдрес);
ПолучаемыеФайлы = Новый Массив;
ПолучаемыеФайлы.Добавить(ПолучаемыйФайл);
ПолученныеФайлы = Новый Массив;
Если ПолучитьФайлы(ПолучаемыеФайлы, ПолученныеФайлы, ЛокальныйПутьКФайлу, Ложь) Тогда
ЗапуститьПриложение(ЛокальныйПутьКФайлу);
Объект.ДоговорРедактируется = Истина;
КонецЕсли;
Исключение
Сообщить(ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
КонецПроцедуры
После того как пользователь отредактировал и сохранил документ на локальном диске, нам необходимо перенести обновленную версию обратно в базу данных. Для этого используем метод ПоместитьФайлы(), который передает файл с клиента во временное хранилище на сервере.
Рассмотрим реализацию клиентской процедуры сохранения и серверного метода записи данных:
&НаКлиенте
Процедура КнопкаСохранить(Команда)
#Если ВебКлиент Тогда
Если НЕ ПодключитьРасширениеРаботыСФайлами() Тогда
УстановитьРасширениеРаботыСФайлами();
ПодключитьРасширениеРаботыСФайлами();
КонецЕсли;
#КонецЕсли
ЛокальныйПутьКФайлу = ОбщиеФункцииКлиент.ВернутьПутьКФайлу(Объект.Номер, Объект.НазваниеИзмененныйДоговор);
Попытка
Если ОбщиеФункцииКлиент.КаталогСуществует(ЛокальныйПутьКФайлу) Тогда
ЗагружаемыйФайл = Новый Файл(ЛокальныйПутьКФайлу);
ПомещаемыеФайлы = Новый Массив;
ПомещаемыеФайлы.Добавить(Новый ОписаниеПередаваемогоФайла(ЛокальныйПутьКФайлу));
ПомещенныеФайлы = Новый Массив;
ПоместитьФайлы(ПомещаемыеФайлы, ПомещенныеФайлы, , Ложь, ЭтаФорма.УникальныйИдентификатор);
СохранитьВерсиюИсполнителя(ПомещенныеФайлы[0].Хранение, ЛокальныйПутьКФайлу, ЗагружаемыйФайл.Размер());
Объект.ДоговорРедактируется = Ложь;
Иначе
Сообщить("Редактируемый файл не найден в каталоге!");
КонецЕсли;
Исключение
Сообщить(ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
&НаСервере
Процедура СохранитьВерсиюИсполнителя(вхВременныйАдрес, вхИмяФайла, вхРазмерФайла)
Если вхВременныйАдрес <> Неопределено Тогда
// Получаем двоичные данные из временного хранилища
ДвоичныеДанные = ПолучитьИзВременногоХранилища(вхВременныйАдрес);
НайденныйФайл = РегистрыСведений.ВременноеХранилищеФайлов.СоздатьНаборЗаписей();
НайденныйФайл.Отбор.ВладелецФайла.Установить(Объект.Ссылка);
НайденныйФайл.Прочитать();
ВремяПериода = ТекущаяДата();
Если НайденныйФайл.Количество() = 0 Тогда
НовоеИмяФайла = "(V1) " + ОбщиеФункцииСервер.ВернутьИмяФайла(вхИмяФайла);
ИмяИсполнителя = ОбщиеФункцииСервер.ТекущийПользователь();
МенеджерЗаписи = РегистрыСведений.ВременноеХранилищеФайлов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Период = ВремяПериода;
МенеджерЗаписи.РазмерФайла = Окр((вхРазмерФайла / 1024) / 1024, 3);
МенеджерЗаписи.ВладелецФайла = Объект.Ссылка;
МенеджерЗаписи.ИмяФайла = НовоеИмяФайла;
МенеджерЗаписи.ДвоичныеДанныеФайла = Новый ХранилищеЗначения(ДвоичныеДанные);
МенеджерЗаписи.ТипФайла = ОбщиеФункцииСервер.ТипИнформации("Основная");
МенеджерЗаписи.АвторФайла = ИмяИсполнителя;
МенеджерЗаписи.Записать();
Объект.НазваниеДоговораИсполнителя = НовоеИмяФайла;
Объект.АвторДоговораИсполнителя = ИмяИсполнителя;
Иначе
Для Каждого Запись Из НайденныйФайл Цикл
Запись.Период = ВремяПериода;
Запись.ДвоичныеДанныеФайла = Новый ХранилищеЗначения(ДвоичныеДанные);
Запись.РазмерФайла = Окр((вхРазмерФайла / 1024) / 1024, 3);
КонецЦикла;
НайденныйФайл.Записать();
КонецЕсли;
Объект.ДатаДоговораИсполнителя = ВремяПериода;
Объект.РазмерДоговораИсполнителя = Окр((вхРазмерФайла / 1024) / 1024, 3);
КонецЕсли;
КонецПроцедуры
Стоит учитывать, что в современных релизах платформы 1С:Предприятие при отключенном режиме использования модальных окон синхронные вызовы (такие как ПодключитьРасширениеРаботыСФайлами, ПолучитьФайлы, ПоместитьФайлы) вызывают ошибку. В асинхронном режиме рекомендуется использовать их асинхронные аналоги с ключевым словом Асинх и оператором Ждать:
ПодключитьРасширениеРаботыСФайламиАсинх()ПолучитьФайлыАсинх() или ПолучитьФайлССервераАсинх()ПоместитьФайлыАсинх() или ПоместитьФайлНаСерверАсинх()ЗапуститьПриложениеАсинх()Подключение расширения работы с файлами и применение правильных процедур помещения/получения файлов из временного хранилища позволяют полноценно организовывать работу с документами в веб-клиенте 1С без использования сторонних сторонних сервисов.