Разберем частую задачу в разработке на платформе 1С:Предприятие 8.3 — открытие файла (например, документа Microsoft Word), который физически сохранен внутри базы данных в реквизите с типом ХранилищеЗначения. Часто разработчики пытаются получить навигационную ссылку на этот реквизит и напрямую передать её в методы запуска приложений, что неизбежно приводит к ошибкам. Давайте проанализируем эту ситуацию и рассмотрим правильные современные способы решения.
Посмотрим на пример кода, который часто пытаются использовать новички:
ТекДок = ПолучитьНавигационнуюСсылку(Объект.Ссылка, "Доки.ДокХранилище", ТекСтр);
НашФайл = Новый Файл(ТекДок);
Попытка
ЗапускПриложения(НашФайл);
Исключение
Сообщить(ОписаниеОшибки());
КонецПопытки;
Выясним причину, по которой этот код выдает ошибку. Функция ПолучитьНавигационнуюСсылку() возвращает строку специального внутреннего формата 1С (например, e1cib/data/Документ...). Однако конструктор объекта Файл ожидает физический путь к файлу на диске (например, C:\Temp\document.docx). Операционная система и метод ЗапускПриложения() ничего не знают о внутренних ссылках 1С, поэтому система не может ни найти такой файл, ни запустить его.
Рассмотрим алгоритм, который был предложен на форуме. Суть заключается в том, чтобы "достать" бинарные данные из базы на сервере, передать их на клиент, сохранить во временную папку операционной системы и только потом открыть.
ХранилищеЗначения в объект ДвоичныеДанные на стороне сервера. Важный нюанс: если данные возвращают Неопределено, убедитесь, что объект был записан в базу перед чтением.ПолучитьИмяВременногоФайла(), обязательно указав правильное расширение файла (например, "docx").Пример реализации:
&НаСервере
Функция ПолучитьФайлИзХранилищаНаСервере(ИндексСтроки)
ТекОбъект = РеквизитФормыВЗначение("Объект");
ТекСтрока = ТекОбъект.Доки.Получить(ИндексСтроки);
Возврат ТекСтрока.ДокХранилище.Получить(); // Возвращает тип ДвоичныеДанные
КонецФункции
&НаКлиенте
Процедура ОткрытьДокумент(Команда)
ДанныеФайла = ПолучитьФайлИзХранилищаНаСервере(Элементы.Доки.ТекущиеДанные.НомерСтроки - 1);
Если ДанныеФайла <> Неопределено Тогда
// Генерируем уникальное имя во временной папке Windows
ПутьКФайлу = ПолучитьИмяВременногоФайла("docx");
// Сохраняем физически на диск клиента
ДанныеФайла.Записать(ПутьКФайлу);
// Открываем. Windows сама подберет Word по расширению .docx
ЗапуститьПриложение(ПутьКФайлу);
КонецЕсли;
КонецПроцедуры
В современных версиях платформы 1С (начиная с 8.3) и особенно для корректной работы в веб-клиенте настоятельно рекомендуется использовать асинхронные методы. Идея с навигационной ссылкой изначально была хорошей, просто нужно использовать правильные функции платформы.
Разберем по шагам, как заставить платформу саму скачать файл по ссылке во временную папку:
НачатьПолучениеФайлаССервера() (или аналогичные асинхронные методы работы с файлами), передав туда нашу ссылку.НачатьЗапускПриложения().Такой подход избавляет нас от необходимости вручную гонять ДвоичныеДанные с сервера на клиент, что сильно экономит оперативную память при работе с большими документами.
Проанализируем ситуацию глобально: хранение файлов напрямую в табличной части документа в реквизите ХранилищеЗначения сегодня считается устаревшей практикой. Это приводит к разрастанию таблиц базы данных и усложняет поддержку.
Если в вашей конфигурации внедрена "Библиотека стандартных подсистем" (БСП), используйте стандартный механизм Присоединенные файлы. В этом случае вам вообще не придется писать низкоуровневый код с временными путями.
Достаточно будет вызвать готовую процедуру:
РаботаСФайламиКлиент.ОткрытьФайл(СсылкаНаПрисоединенныйФайл);
Что сделает БСП под капотом:
Применяйте современные методы разработки, старайтесь избегать синхронных вызовов вроде ЗапускПриложения() в новых конфигурациях и всегда очищайте за собой временные каталоги, если бизнес-логика не подразумевает дальнейшего использования выгруженных на жесткий диск файлов.