Как правильно загружать, хранить и открывать файлы из Хранилища Значения в 1С:Предприятии 8.3

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Работа с прикрепленными файлами — одна из самых частых задач при разработке на платформе 1С:Предприятие 8.3. Однако из-за разделения контекста выполнения кода на клиентский и серверный программисты часто сталкиваются со сложностями. Типичные симптомы неправильной реализации — зависание интерфейса, ошибки доступа к локальным путям на сервере или критическая ошибка веб-сервера "HTTP: Not acceptable Ошибка при работе с ресурсом /e1cib/files?cmd=GetInfoBaseFileURL".

В этой статье мы подробно разберем, почему возникают подобные проблемы, как устроена работа с временным хранилищем и как реализовать надежный, современный механизм загрузки и открытия файлов в управляемых формах 1С.

Выясняем причину ошибки "HTTP: Not acceptable..."

Прежде чем перейти к правильному коду, проанализируем ситуацию, описанную в сообщениях форума. Автор темы пытался передать на сервер локальный путь к каталогу документов, получить там файл по имени, поместить его во временное хранилище и вернуть на клиент. В процессе возникла ошибка веб-сервера HTTP: Not acceptable.

Эта ошибка указывает на то, что клиентское приложение (особенно при работе через веб-клиент) попыталось обратиться к временному хранилищу по некорректному или пустому адресу. Разберем цепочку действий, которая привела к сбою:

  1. На клиенте был получен путь к каталогу (например, "C:\Users\Username\Documents\").
  2. Этот путь был передан на сервер в процедуру поиска файла: СтруктураФайла = Справочники.ХранилищеФайлов.НайтиПоНаименованию(ИмяФайла);. Но вместо имени файла туда попал путь к каталогу!
  3. Поиск вернул пустую ссылку, так как элемента справочника с именем каталога в базе нет.
  4. При попытке прочитать реквизит Файлы у пустой ссылки система вернула Неопределено.
  5. Значение Неопределено было помещено во временное хранилище. Адрес этого пустого хранилища вернулся на клиент.
  6. Когда клиентский метод НачатьПолучениеФайлов() попытался скачать данные по этому некорректному адресу, веб-сервер выдал ошибку 406 Not Acceptable, так как запрашиваемый ресурс не содержал валидного файла.

Кроме того, старые методы работы с файлами (такие как НачатьПолучениеФайлов, НачатьПомещениеФайла) требуют громоздких описаний оповещений и ручного контроля временных папок. Рассмотрим, как решить эту задачу изящно и современно.

Современный метод загрузки файла в базу данных

Начиная с версии платформы 1С 8.3.15, разработчикам доступен оптимизированный метод асинхронного помещения файлов на сервер. Вместо ручного создания двоичных данных на клиенте и их записи во временные файлы, мы будем использовать метод НачатьПомещениеФайлаНаСервер().

Рассмотрим по шагам правильную схему загрузки файла в справочник-хранилище.

Шаг 1. Клиентская часть. Вызов диалога выбора файла

На клиенте мы инициируем интерактивный выбор файла. Платформа самостоятельно считает файл с диска пользователя и поместит его в безопасное временное хранилище на сервере, вернув нам лишь адрес.


&НаКлиенте
Процедура ЗагрузитьФайлВыполнить(Команда)
    
    // Настраиваем параметры диалога выбора файла
    ПараметрыПомещения = Новый ПараметрыДиалогаПомещенияФайлов;
    ПараметрыПомещения.МножественныйВыбор = Ложь;
    ПараметрыПомещения.Заголовок = "Выберите файл для загрузки в хранилище";
    
    Оповещение = Новый ОписаниеОповещения("ПослеВыбораФайла", ЭтотОбъект);
    
    // Запускаем асинхронное помещение файла на сервер
    НачатьПомещениеФайлаНаСервер(Оповещение, , , "", ПараметрыПомещения, УникальныйИдентификатор);
    
КонецПроцедуры

Шаг 2. Клиентская часть. Обработка результата выбора

После того как пользователь выбрал файл и платформа загрузила его во временное хранилище, срабатывает процедура оповещения. Обратите внимание: мы не передаем на сервер пути к файлам — только адрес во временном хранилище и имя файла.


&НаКлиенте
Процедура ПослеВыбораФайла(РезультатПомещения, ДополнительныеПараметры) Экспорт
    
    // Если пользователь закрыл диалог выбора файла
    Если РезультатПомещения = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Извлекаем адрес во временном хранилище и имя исходного файла
    АдресХранилища = РезультатПомещения.Адрес;
    ИмяВыбранногоФайла = РезультатПомещения.СсылкаНаФайл.Имя;
    
    // Вызываем серверную процедуру для записи файла в базу данных
    СоздатьЭлементХранилищаНаСервере(АдресХранилища, ИмяВыбранногоФайла);
    
    Модифицированность = Истина;
    ПоказатьОповещениеПользователя("Успех", , "Файл успешно загружен в базу данных!");
    
КонецПроцедуры

Шаг 3. Серверная часть. Создание элемента справочника

На сервере мы извлекаем двоичные данные из временного хранилища и записываем их в реквизит с типом ХранилищеЗначения. Хранить данные лучше в чистом виде (как ДвоичныеДанные), а имя файла и его расширение записывать в отдельные текстовые реквизиты справочника.


&НаСервере
Процедура СоздатьЭлементХранилищаНаСервере(АдресХранилища, ИмяФайла)
    
    // Извлекаем двоичные данные из временного хранилища
    ДвоичныеДанныеФайла = ПолучитьИзВременногоХранилища(АдресХранилища);
    
    Если ТипЗнч(ДвоичныеДанныеФайла) <> Тип("ДвоичныеДанные") Тогда
        ВызватьИсключение "Не удалось получить корректные данные файла.";
    КонецЕсли;
    
    // Создаем новый элемент справочника для хранения файлов
    НовыйФайл = Справочники.ХранилищеФайлов.СоздатьЭлемент();
    НовыйФайл.Наименование = ИмяФайла;
    НовыйФайл.ИмяФайла = ИмяФайла;
    НовыйФайл.ВладелецФайла = Объект.Ссылка;
    
    // Помещаем двоичные данные в ХранилищеЗначения
    НовыйФайл.ДанныеФайла = Новый ХранилищеЗначения(ДвоичныеДанныеФайла, Новый СжатиеДанных(9));
    
    НовыйФайл.Записать();
    
КонецПроцедуры

Как правильно и быстро открыть файл из ХранилищаЗначения

Для открытия сохраненного файла нам не нужно вручную скачивать его на диск во временные папки и использовать НачатьЗапускПриложения. В платформе 1С предусмотрен мощный универсальный механизм — получение файла по навигационной ссылке.

Если реквизит справочника имеет тип ХранилищеЗначения, мы можем получить на него прямую навигационную ссылку и передать ее стандартной процедуре получения файлов. Платформа сама определит тип клиента, скачает файл во временный каталог операционной системы и запустит ассоциированное с ним приложение (например, Microsoft Word, Excel или просмотрщик PDF).

Ниже представлены два варианта реализации открытия файла: для современных платформ (8.3.18+) с использованием механизма Асинх / Ждать и для более ранних версий через обратные вызовы (Оповещения).

Вариант 1. Самый простой и современный метод (для платформ 8.3.18+)

Использование конструкции Ждать позволяет писать понятный линейный код без создания дополнительных процедур-оповещений.


&НаКлиенте
Асинх Процедура СписокФайловВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    
    ТекущиеДанные = Элементы.СписокФайлов.ТекущиеДанные;
    Если ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Получаем навигационную ссылку на реквизит "ДанныеФайла" конкретного элемента справочника
    СсылкаНаФайлВБД = ПолучитьНавигационнуюСсылку(ТекущиеДанные.Ссылка, "ДанныеФайла");
    
    ПараметрыПолучения = Новый ПараметрыДиалогаПолученияФайлов;
    
    // Метод скачает файл на клиентский компьютер и запустит программу просмотра
    Ждать ПолучитьФайлССервераАсинх(СсылкаНаФайлВБД, ТекущиеДанные.ИмяФайла, ПараметрыПолучения);
    
КонецПроцедуры

Вариант 2. Метод через ОписаниеОповещения (совместим с 1С 8.3.15 – 8.3.17)

Если вы работаете на более старых версиях платформы 8.3, используйте метод НачатьПолучениеФайлаССервера() с обратным вызовом.


&НаКлиенте
Процедура СписокФайловВыборАльтернативный(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    
    ТекущиеДанные = Элементы.СписокФайлов.ТекущиеДанные;
    Если ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    СсылкаНаФайлВБД = ПолучитьНавигационнуюСсылку(ТекущиеДанные.Ссылка, "ДанныеФайла");
    ПараметрыПолучения = Новый ПараметрыДиалогаПолученияФайлов;
    
    Оповещение = Новый ОписаниеОповещения("ПослеПолученияФайлаССервера", ЭтотОбъект);
    
    НачатьПолучениеФайлаССервера(Оповещение, СсылкаНаФайлВБД, ТекущиеДанные.ИмяФайла, ПараметрыПолучения);
    
КонецПроцедуры

&НаКлиенте
Процедура ПослеПолученияФайлаССервера(РезультатПолучения, ДополнительныеПараметры) Экспорт
    
    // Файл был успешно загружен и запущен на клиенте
    // Здесь можно выполнить дополнительные действия, если необходимо
    
КонецПроцедуры

Архитектурные рекомендации по хранению файлов в 1С

Хотя хранение двоичных данных непосредственно в базе данных (в реквизитах типа ХранилищеЗначения) реализовать проще всего, этот подход имеет серьезные недостатки при росте объема базы данных. Рассмотрим несколько важных советов по улучшению архитектуры вашего решения:

Применение современных асинхронных вызовов платформы 1С:Предприятие 8.3 позволяет полностью избежать зависания интерфейса у пользователей и гарантирует корректную работу приложения как на тонком клиенте, так и при публикации базы на веб-сервере под управлением Apache или IIS.

← На главную