Задача прикрепления и открытия нескольких файлов к элементам управляемых форм в 1С является довольно распространенной, но при этом часто вызывает вопросы у разработчиков, особенно когда речь идет о корректном хранении и последующем доступе к файлам. Мы с вами рассмотрим подробнее, как организовать этот процесс, избегая распространенных ошибок и используя наиболее эффективные подходы.
Основная сложность заключается в том, чтобы правильно сохранить данные файлов таким образом, чтобы они были доступны для последующего открытия на клиентском компьютере. Существуют два основных пути решения этой задачи, каждый из которых имеет свои особенности и область применения.
Мы проанализируем два основных подхода к прикреплению и открытию файлов:
ХранилищеЗначений и функций для клиент-серверного взаимодействия с файлами. Этот вариант подходит, если интеграция БСП нежелательна или избыточна для ваших требований.Если в вашей конфигурации уже используется БСП или вы готовы ее внедрить, то самым надежным и функциональным решением будет интеграция подсистемы "Работа с файлами". Эта подсистема разработана фирмой "1С" и предлагает готовый, проверенный временем механизм для всех операций с файлами.
Преимущества БСП:
ХранилищеЗначений), так и во внешних томах (на сетевых дисках), что важно для больших файлов.Как работает подсистема "Работа с файлами" в БСП:
В БСП файлы хранятся в специализированных справочниках (например, "ПрисоединенныеФайлы"), которые связаны с объектами конфигурации (документами, справочниками), к которым они прикреплены. Сами данные файлов могут храниться либо непосредственно в базе данных (в виде ХранилищеЗначений), либо во внешних томах (на сетевых дисках), что настраивается администратором.
Общие шаги по внедрению подсистемы "Работа с файлами" из БСП:
ДокументСсылка.МойДокумент).Важный момент, касающийся БСП:
Как справедливо отмечают участники форума, при работе с БСП критически важно понимать, что мы не просто копируем отдельные функции, а интегрируем всю подсистему. Отдельные функции БСП, вырванные из контекста, скорее всего, работать не будут, так как они зависят от множества других объектов, модулей и настроек, которые являются частью комплексного решения. Если мы попытаемся использовать только "руль от велосипеда", мы никуда не уедем. БСП автоматически обрабатывает все процессы: от сохранения файла на сервер до его извлечения из ХранилищаЗначений (или внешнего тома) и передачи на клиент для открытия, а также управление временными файлами. Для быстрого изучения и поиска готовых примеров работы с функциями библиотеки пригодится справочник по методам БСП с примерами использования.
Если по каким-то причинам интеграция БСП невозможна или вы хотите иметь более легкое и минималистичное решение без зависимостей от большой библиотеки, мы можем реализовать собственный механизм прикрепления и открытия файлов. Этот подход потребует более детальной проработки и управления файлами вручную.
Для хранения информации о нескольких файлах в управляемой форме мы будем использовать табличную часть. В каждую строку этой табличной части мы добавим реквизиты, необходимые для идентификации и хранения файла:
ИмяФайла (Тип: Строка) — для отображения полного имени файла пользователю (например, "Отчет.pdf").Расширение (Тип: Строка) — для определения типа файла при открытии (например, "pdf", "docx").Размер (Тип: Число) — для информации о размере файла в байтах.ДанныеФайла (Тип: ХранилищеЗначений) — этот реквизит будет хранить содержимое файла в бинарном виде непосредственно в базе данных. Это ключевой реквизит для хранения самих данных файла.Процесс прикрепления файла:
При прикреплении файла нам потребуется получить его с клиентского компьютера, передать на сервер и сохранить в реквизите ДанныеФайла:
ХранилищеЗначений.ХранилищеЗначений мы запишем в реквизит ДанныеФайла новой строки табличной части.Рассмотрим пример кода для прикрепления файла:
// Пример на клиенте: Выбор файла и передача его на сервер для сохранения
&НаКлиенте
Процедура ПрикрепитьФайл()
ДиалогВыбораФайла = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
ДиалогВыбораФайла.Заголовок = "Выберите файл для прикрепления";
ДиалогВыбораФайла.МножественныйВыбор = Ложь; // Указываем, что можно выбрать только один файл
Если ДиалогВыбораФайла.Выбрать() Тогда
ПолноеИмяФайлаНаКлиенте = ДиалогВыбораФайла.ПолноеИмяФайла;
ИмяФайла = ДиалогВыбораФайла.ИмяФайла;
// Вызываем серверную процедуру для сохранения файла
// В параметрах передаем полный путь к файлу на клиенте и его имя
СохранитьФайлНаСервере(ПолноеИмяФайлаНаКлиенте, ИмяФайла);
КонецЕсли;
КонецПроцедуры
// Пример на сервере: Сохранение файла в ХранилищеЗначений
&НаСервере
Процедура СохранитьФайлНаСервере(ПолноеИмяФайлаНаКлиенте, ИмяФайла)
// Читаем файл с клиента в двоичные данные на сервере
// Функция Новый ДвоичныеДанные(ПолноеИмяФайлаНаКлиенте) автоматически передает файл
ДвоичныеДанные = Новый ДвоичныеДанные(ПолноеИмяФайлаНаКлиенте);
// Создаем ХранилищеЗначений из двоичных данных.
// Можно использовать сжатие для экономии места в базе.
Хранилище = Новый ХранилищеЗначений(ДвоичныеДанные, Новый СжатиеДанных(9));
// Добавляем новую строку в нашу табличную часть
// Предполагаем, что у нашей формы есть реквизит "Объект"
// и у "Объекта" есть табличная часть с именем "ПрикрепленныеФайлы"
НоваяСтрока = Объект.ПрикрепленныеФайлы.Добавить();
НоваяСтрока.ИмяФайла = ИмяФайла;
НоваяСтрока.Расширение = ОбщегоНазначенияКлиентСервер.ПолучитьРасширениеФайла(ИмяФайла);
НоваяСтрока.Размер = ДвоичныеДанные.Размер();
НоваяСтрока.ДанныеФайла = Хранилище;
КонецПроцедуры
Для открытия файла, сохраненного в ХранилищеЗначений, нам потребуется выполнить следующие шаги, поскольку файл из базы данных нельзя открыть напрямую:
ДвоичныеДанные из ХранилищаЗначений на сервере.ДвоичныеДанные во временный файл на сервере.НачатьПолучениеФайлаССервера().ЗапуститьПриложение() для его открытия стандартным приложением операционной системы.Рассмотрим пример кода для открытия файла:
// Пример на клиенте: Обработчик события для открытия файла (например, по клику на имя файла)
&НаКлиенте
Процедура ПрикрепленныеФайлыИмяФайлаНажатие(Элемент, СтандартнаяОбработка)
Если Элементы.ПрикрепленныеФайлы.ТекущиеДанные = Неопределено Тогда
Возврат;
КонецЕсли;
// Получаем текущую строку табличной части, из которой хотим открыть файл
СтрокаТЧ = Элементы.ПрикрепленныеФайлы.ТекущиеДанные;
// Вызываем серверную функцию, чтобы получить путь к временному файлу на сервере
// Файл будет извлечен из ХранилищаЗначений и временно сохранен на сервере
ПутьКФайлуНаСервере = ПолучитьПутьКФайлуИзХранилищаНаСервере(СтрокаТЧ.ДанныеФайла, СтрокаТЧ.ИмяФайла);
Если ПутьКФайлуНаСервере <> Неопределено Тогда
// Подготавливаем описание оповещения. Это обратный вызов,
// который будет выполнен на клиенте после завершения получения файла.
ОписаниеОповещения = Новый ОписаниеОповещения("ПослеПолученияФайла", ЭтотОбъект, ПутьКФайлуНаСервере);
// Начинаем асинхронное получение файла с сервера на клиент.
// Первый параметр - путь к файлу на сервере.
// Второй параметр (Истина) - указание удалить временный файл на сервере после получения.
// Третий параметр - наше оповещение.
// Четвертый параметр - имя файла, под которым он будет сохранен на клиенте.
НачатьПолучениеФайлаССервера(ПутьКФайлуНаСервере, Истина, ОписаниеОповещения, СтрокаТЧ.ИмяФайла);
КонецЕсли;
КонецПроцедуры
// Процедура-обработчик после получения файла с сервера (выполняется на клиенте)
&НаКлиенте
Процедура ПослеПолученияФайла(ПолноеИмяФайлаНаКлиенте, ДополнительныеПараметры) Экспорт
Если ПолноеИмяФайлаНаКлиенте <> Неопределено Тогда
// Файл успешно загружен на клиент во временную папку. Теперь можем его открыть.
ЗапуститьПриложение(ПолноеИмяФайлаНаКлиенте);
// Важно: временный файл на клиенте необходимо удалить, чтобы не засорять диск.
// Это можно сделать, например, при закрытии формы или через короткий промежуток времени.
// Для демонстрации мы просто сообщаем о пути.
// Сообщить("Файл сохранен на клиенте во временный файл: " + ПолноеИмяФайлаНаКлиенте);
// Например, можно добавить вызов для удаления файла после задержки
// СоздатьФоновоеЗаданиеДляУдаления(ПолноеИмяФайлаНаКлиенте); // Гипотетическая серверная функция
Иначе
Сообщить("Не удалось получить файл с сервера.");
КонецЕсли;
КонецПроцедуры
// Серверная функция: извлечение файла из хранилища и сохранение его во временный файл на сервере
&НаСервере
Функция ПолучитьПутьКФайлуИзХранилищаНаСервере(ХранилищеФайла, ИмяФайла)
Попытка
ДвоичныеДанные = ХранилищеФайла.Получить(); // Извлекаем двоичные данные из ХранилищаЗначений
Исключение
Сообщить("Не удалось получить данные файла из хранилища: " + ОписаниеОшибки());
Возврат Неопределено;
КонецПопытки;
Если ДвоичныеДанные = Неопределено Тогда
Сообщить("В хранилище нет данных.");
Возврат Неопределено;
КонецЕсли;
// Генерируем уникальное имя для временного файла на сервере.
// Это важно, чтобы избежать конфликтов при одновременной работе нескольких пользователей.
ПолноеИмяВременногоФайлаНаСервере = ПолучитьКаталогВременныхФайлов() + УникальныйИдентификатор() + "_" + ИмяФайла;
Попытка
ДвоичныеДанные.Записать(ПолноеИмяВременногоФайлаНаСервере); // Сохраняем двоичные данные во временный файл
Возврат ПолноеИмяВременногоФайлаНаСервере; // Возвращаем путь к этому временному файлу на сервере
Исключение
Сообщить("Ошибка при сохранении временного файла на сервере: " + ОписаниеОшибки());
Возврат Неопределено;
КонецПопытки;
КонецФункции
Функции НачатьПолучениеФайлаССервера() и ЗапуститьПриложение():
НачатьПолучениеФайлаССервера(ПутьКФайлуНаСервере, УдалятьФайлНаСервере, ОписаниеОповещения, ИмяФайлаНаКлиенте): Эта клиентская асинхронная функция инициирует процесс загрузки файла с сервера на клиентский компьютер. В качестве первого параметра мы передаем полный путь к временному файлу, который был создан на сервере. Параметр УдалятьФайлНаСервере (Истина) указывает системе, что временный файл на сервере должен быть удален сразу после успешной передачи, что очень важно для поддержания чистоты на сервере. Результат (путь к загруженному файлу на клиенте) передается в процедуру-обработчик, указанную в ОписаниеОповещения.
ЗапуститьПриложение(ПолноеИмяФайла): Эта клиентская функция является универсальным способом открытия любого файла по его полному пути на клиентском компьютере. Она запускает стандартную программу операционной системы, ассоциированную с расширением указанного файла. Например, для файла ".docx" будет запущен Microsoft Word, для ".pdf" — Adobe Reader и так далее. Важно, что к моменту вызова этой функции файл уже должен быть физически расположен на клиентском компьютере (например, в его временной директории).
Обратите внимание, что упомянутая в исходном сообщении функция ПолучитьНавигационнуюСсылку(Объект.Ссылка, "Файл") обычно используется для получения ссылки на файлы, прикрепленные к объектам конфигурации через стандартные механизмы 1С (например, когда документ имеет поддержку прикрепленных файлов). В нашем случае, при ручном хранении файлов в ХранилищеЗначений в табличной части, мы управляем временными файлами и их передачей вручную, а не через предопределенные навигационные ссылки.
Мы видим, что для решения задачи прикрепления и открытия нескольких файлов в управляемых формах 1С существуют два основных пути. Выбор между ними зависит от требований к функциональности, сложности проекта и наличия БСП в вашей конфигурации. Использование БСП является предпочтительным, так как предоставляет готовое, мощное и поддерживаемое решение, снимая с нас большую часть ручной работы и управления сложностями клиент-серверного взаимодействия.
Ручная реализация с ХранилищемЗначений требует более глубокого понимания механизмов клиент-серверного взаимодействия и тщательной проработки деталей, особенно в части создания, передачи и удаления временных файлов на обеих сторонах. В любом случае, крайне важно понимать, что для открытия файла на клиентском компьютере он должен физически присутствовать на этом компьютере (пусть даже как временный файл). Функция ЗапуститьПриложение() затем вызывает соответствующую программу для открытия файла по его локальному пути. Для организации просмотра документов без запуска внешних программ можно использовать расширение для встроенного предпросмотра файлов популярных форматов.
Надеемся, что этот подробный разбор поможет вам успешно реализовать функциональность прикрепления и открытия файлов в ваших конфигурациях 1С.