В качестве примера рассмотрим задачу получения файла с клиентского компьютера и сохранения его в реквизите справочника.
Примечание
Пример можно посмотреть в базе «Файлы и картинки», справочник Поставщики.
Пусть в конфигурации существует справочник Поставщики. Для каждого поставщика в базе данных должен храниться произвольный файл, содержащий договор с этим поставщиком.
Сразу оговоримся, что рассматриваемый пример упрощен и произвольный файл мы будем хранить в одном из реквизитов самого справочника Поставщики. В реальной работе, как правило, так не поступают.
Для хранения больших объемов бинарных данных (файлы, картинки) создаются отдельные объекты конфигурации (справочники или регистры сведений), связанные с данным объектом. Такой подход позволяет исключить обязательное считывание больших объемов информации при считывании самого объекта.
Итак, справочник Поставщики будет содержать два реквизита: ФайлДоговора (типа ХранилищеЗначения для хранения двоичных данных) и ИмяФайлаДоговора (типа Строка для хранения имени загруженного файла), рис. 3.154.

Рис. 3.154. Структура справочника «Поставщики»
Имя загруженного файла понадобится нам для того, чтобы иметь возможность в дальнейшем этот файл поместить обратно на компьютер пользователя.
Форма элемента справочника Поставщики помимо данных самого объекта будет содержать два дополнительных строковых реквизита: ИмяФайлаДоговора и СсылкаНаФайлВоВременномХранилище (рис. 3.155).

Рис. 3.155. Реквизиты формы элемента справочника «Поставщики»
Ссылка на временное хранилище запоминается в форме потому, что она необходима лишь на момент от загрузки файла до записи объекта в базу данных и не является частью прикладных данных объекта.
ИмяФайлаДоговора запоминается в форме для того, чтобы не модифицировать данные объекта до тех пор, пока не начнется запись объекта в базу данных. В принципе, можно обойтись и без него – сохранять имя файла прямо в реквизит объекта, но тогда несколько сложнее станет проверка, выполняемая при сохранении файла на компьютер пользователя.
Для загрузки файла с диска в информационную базу и для сохранения его на диск в форме созданы две локальные команды: ЗагрузитьСДиска и СохранитьНаДиск.
Загрузка файла выполняется с помощью немодального метода глобального контекста НачатьПомещениеФайла(). Первым параметром в этот метод передается описание оповещения, описывающее экспортную процедуру (расположенную в том же модуле – модуле формы) ЗагрузитьСДискаЗавершение(), которая будет вызвана, когда пользователь выберет файл (листинг 3.129).
В этой процедуре обработки оповещения в случае выбора файла пользователем и будут выполняться действия по загрузке файла с диска (листинг 3.130).
Листинг 3.129. Загрузка файла
&НаКлиенте
Процедура ЗагрузитьСДиска(Команда)
НачатьПомещениеФайла(Новый ОписаниеОповещения("ЗагрузитьСДискаЗавершение", ЭтотОбъект), , , Истина , УникальныйИдентификатор);
КонецПроцедуры
Помимо описания оповещения в метод НачатьПомещениеФайла() четвертым параметром передается Истина – признак интерактивного выбора файла. И пятым параметром передается уникальный идентификатор открытой формы, о котором речь пойдет ниже.
Листинг 3.130. Обработчик оповещения «ЗагрузитьСДискаЗавершение»
&НаКлиенте
Процедура ЗагрузитьСДискаЗавершение(Результат, АдресВХранилище, ВыбранноеИмяФайла, ДополнительныеПараметры) Экспорт
Если Результат Тогда
Файл = Новый Файл(ВыбранноеИмяФайла);
ИмяФайлаДоговора = Файл.Имя;
СсылкаНаФайлВоВременномХранилище = АдресВХранилище;
Модифицированность = Истина;
КонецЕсли;
КонецПроцедуры
В процедуру, вызывающуюся после выбора файла, в параметре Результат передается признак того, что пользователь осуществил выбор файла. Потому что в процессе выбора файла пользователь может, вообще говоря, отказаться от задуманной операции – загрузки файла. Поэтому модификация реквизитов формы выполняется только в том случае, когда файл выбран успешно.
В параметре АдресВХранилище передается адрес во временном хранилище, по которому был помещен файл. И в параметре ВыбранноеИмяФайла передается путь к выбранному файлу.
В случае успешного выбора файла короткое имя файла помещается в реквизит формы ИмяФайлаДоговора, а ссылка на этот файл во временном хранилище помещается в реквизит формы СсылкаНаФайлВоВременномХранилище.
Для того чтобы из полного имени файла получить короткое имя, используется программный объект Файл (листинг 3.131).
Листинг 3.131. Получение короткого имени файла
Файл = Новый Файл(ВыбранноеИмяФайла);
ИмяФайлаДоговора = Файл.Имя;
Немного отступим от нашего примера, чтобы дать полезный совет. Быстро и без ошибок создать заготовку процедуры обработки оповещения и сконструировать объект ОписаниеОповещения при вызове немодального метода можно с помощью механизма рефакторинга. Для этого достаточно написать имя метода, поставить открывающую скобку (например, «НачатьПомещениеФайла()»), установить курсор на имя метода и вызвать из контекстного меню команду Рефакторинг – Создать обработку оповещения. Затем в отдельном окне можно задать имя процедуры обработки оповещения или согласиться с тем именем, которое предлагает платформа (рис. 3.156).

Рис. 3.156. Создание обработки оповещения с помощью рефакторинга
Вернемся к нашему примеру. Итак, после помещения файл окажется во временном хранилище, а в реквизитах формы будет ссылка на него и его имя (рис. 3.157).

Рис. 3.157. Файл во временном хранилище
Примечательным здесь является то, что при помещении файла мы указали последний параметр метода НачатьПомещениеФайла() (листинг 3.132).
Листинг 3.132. Привязка файла к открытой форме
НачатьПомещениеФайла(Новый ОписаниеОповещения("ЗагрузитьСДискаЗавершение", ЭтотОбъект), , , Истина , УникальныйИдентификатор);
В качестве этого параметра мы передали уникальный идентификатор нашей открытой формы. Это значит, что файл во временном хранилище будет существовать до тех пор, пока мы не закроем форму. Тогда платформа автоматически удалит его из хранилища. Значит, если пользователь откажется от сохранения изменений, сделанных в форме, нам не нужно заботиться об удалении файла из временного хранилища – платформа это сделает сама.
А вот если пользователь решит сохранить сделанные изменения, тогда будут выполнены следующие действия.
Сначала на сервере будет вызван обработчик события формы Перед записью на сервере (листинг 3.133).
Листинг 3.133. Обработчик события «Перед записью на сервере»
&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// Получить файл из хранилища и поместить его в объект.
Если ЭтоАдресВременногоХранилища(СсылкаНаФайлВоВременномХранилище) Тогда
ДвоичныеДанные = ПолучитьИзВременногоХранилища(СсылкаНаФайлВоВременномХранилище);
ТекущийОбъект.ФайлДоговора = Новый ХранилищеЗначения(ДвоичныеДанные, Новый СжатиеДанных(9));
ТекущийОбъект.ИмяФайлаДоговора = ИмяФайлаДоговора;
КонецЕсли;
КонецПроцедуры
В этом обработчике мы поместим файл из временного хранилища в реквизит записываемого объекта, и в другой реквизит объекта поместим имя этого файла. Делать это мы будем не всегда (ведь пользователь может записать объект, и не указывая файл договора), а только в том случае, когда реквизит формы действительно хранит ссылку на файл во временном хранилище (листинг 3.134).
Листинг 3.134. Проверка того, что навигационная ссылка указывает на временное хранилище
Если ЭтоАдресВременногоХранилища(СсылкаНаФайлВоВременномХранилище) Тогда
В этом случае мы получим из временного хранилища двоичные данные и преобразуем их в объект ХранилищеЗначения, который и поместим в реквизит записываемого объекта (листинг 3.135).
Листинг 3.135. Помещение файла в реквизит объекта
ДвоичныеДанные = ПолучитьИзВременногоХранилища(СсылкаНаФайлВоВременномХранилище);
ТекущийОбъект.ФайлДоговора = Новый ХранилищеЗначения(ДвоичныеДанные, Новый СжатиеДанных(9));
Таким образом, после выполнения этого обработчика мы будем иметь следующую картину (рис. 3.158).

Рис. 3.158. Файл в реквизите объекта
Затем платформа начнет запись объекта, и его данные будут помещены в базу данных (рис. 3.159).

Рис. 3.159. Запись данных объекта в базу данных
После этого, еще до окончания транзакции записи, на сервере будет вызван обработчик события формы При записи на сервере (листинг 3.136).
Листинг 3.136. Обработчик события «При записи на сервере»
&НаСервере
Процедура ПриЗаписиНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// Удалить файл из временного хранилища
Если ЭтоАдресВременногоХранилища(СсылкаНаФайлВоВременномХранилище) Тогда
УдалитьИзВременногоХранилища(СсылкаНаФайлВоВременномХранилище);
КонецЕсли;
КонецПроцедуры
В этом обработчике мы «наведем красоту». Так как данные объекта уже записаны в базу данных, полученный файл успешно сохранен, можно удалить из временного хранилища находящийся там файл. Для этого мы используем ссылку, сохраненную в реквизите формы (рис. 3.160).

Рис. 3.160. Удаление файла из временного хранилища
Теоретически можно этого и не делать: платформа все равно автоматически удалит этот файл, когда мы закроем форму. Но в общем случае при интенсивной многопользовательской работе лучше освобождать ресурсы сервера сразу же после того, как необходимость в них исчезает.
Процесс получения файла из информационной базы выглядит гораздо проще. Он целиком реализован в обработчике локальной команды формы СохранитьНаДиск (листинг 3.137).
Листинг 3.137. Получение файла из информационной базы
&НаКлиенте
Процедура СохранитьНаДиск(Команда)
Если Объект.ИмяФайлаДоговора = "" Тогда
ПоказатьПредупреждение(, "У поставщика нет сохраненного в базе договора");
Иначе
СсылкаНаФайлВИБ = ПолучитьНавигационнуюСсылку(Объект.Ссылка, "ФайлДоговора");
ПолучитьФайл(СсылкаНаФайлВИБ, Объект.ИмяФайлаДоговора);
КонецЕсли;
КонецПроцедуры
Поскольку имя файла договора мы записываем в реквизит объекта только в момент записи, можно использовать его для определения того, есть ли в объекте сохраненный файл или нет.
Если нет, то показываем пользователю сообщение с помощью немодального метода ПоказатьПредупреждение(). Первый параметр – описание оповещения – в этом вызове опущен, так как после вывода предупреждения никаких действий выполнять не требуется.
Чтобы получить файл из информационной базы, нужно иметь навигационную ссылку на этот файл.
Навигационную ссылку мы получаем, указывая ссылку на объект и указывая имя реквизита объекта, в котором хранится файл (листинг 3.138).
Листинг 3.138. Получение навигационной ссылки на реквизит объекта
СсылкаНаФайлВИБ = ПолучитьНавигационнуюСсылку(Объект.Ссылка, "ФайлДоговора");
Затем просто получаем файл по ссылке СсылкаНаФайлВИБ и сохраняем его на компьютер пользователя с именем, заданным в реквизите ИмяФайлаДоговора (листинг 3.139).
Листинг 3.139. Получение файла на компьютер пользователя
ПолучитьФайл(СсылкаНаФайлВИБ, Объект.ИмяФайлаДоговора);
При выполнении этого метода будет открыт стандартный диалог операционной системы, который предложит либо открыть, либо сохранить получаемый файл (рис. 3.161).

Рис. 3.161. Диалог получения файла