Файл лежит в базе 1С как двоичные данные: как достать и открыть

· 9 мин

Содержание

Пользователь прислал скан договора, а в карточке контрагента вместо файла видна строка «Двоичные данные». Или в консоли запросов в колонке стоит ДвоичныеДанные и ничего не открывается. Это нормально: 1С не показывает содержимое двоичных данных, их нужно сначала записать в файл на диск, а потом открыть программой, которая понимает формат.

Короткий путь такой: получить значение типа ДвоичныеДанные, вызвать у него метод Записать(ИмяФайла) и открыть получившийся файл. Всё остальное зависит от того, где именно лежат данные: в реквизите, в ХранилищеЗначения, в макете или на стороне другой системы.

Что такое двоичные данные и где они прячутся

Тип ДвоичныеДанные хранит набор байт без указания формата. Расширение файла, имя и тип содержимого в нём не записаны. Поэтому имя и расширение вы задаёте сами или берёте из соседнего реквизита.

Чаще всего двоичные данные встречаются в таких местах:

  • 📎 присоединённые файлы документов и справочников (скан, PDF, картинка);
  • 🗄 реквизиты типа ХранилищеЗначения, куда программисты кладут вложения;
  • 📄 макеты конфигурации с типом «Двоичные данные»;
  • 🌐 ответы внешних сервисов и содержимое писем;
  • 🔤 строки в формате Base64, которые пришли из обмена.

Если вы видите в списке слово «Хранилище» или «Двоичные данные» вместо имени файла, значит, содержимое надо извлекать кодом или штатной кнопкой формы. Узнайте у разработчика, как называется реквизит, прежде чем писать код: это сэкономит час поисков.

Если в форме есть кнопка: открываем без кода

Присоединённые файлы в типовых конфигурациях открываются штатно. Откройте документ или карточку, найдите ссылку «Файлы» или значок скрепки, выберите файл и нажмите «Открыть» либо «Сохранить как». 1С сама запишет данные во временный каталог и запустит нужную программу.

Если кнопки нет, а файл в базе точно есть, проверьте права: у роли может быть закрыто чтение присоединённых файлов. Это решается правами, а не кодом.

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

Запись двоичных данных на диск встроенным языком

Это универсальный способ. Подходит для внешней обработки, расширения и консоли кода.

Предположим, у вас есть ссылка на элемент справочника с реквизитом ДанныеФайла типа ДвоичныеДанные:

Данные = Элемент.ДанныеФайла;          // значение типа ДвоичныеДанные
Путь = ПолучитьИмяВременногоФайла("pdf");
Данные.Записать(Путь);

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

Чтобы сразу открыть результат на клиенте, добавьте:

НачатьЗапускПриложения(Новый ОписаниеОповещения("ПослеЗапуска", ЭтотОбъект), Путь);

В старых формах встречается синхронный ЗапуститьПриложение(Путь). Оно работает в толстом клиенте, а в веб-клиенте часть таких вызовов недоступна.

Что делать на сервере, если пользователь работает на клиенте

Клиент и сервер видят разные файловые системы. Записать файл в C:\Temp на сервере бесполезно: у пользователя его не будет. Правильная цепочка такая:

  1. На сервере положите данные во временное хранилище: Адрес = ПоместитьВоВременноеХранилище(Данные, УникальныйИдентификатор);
  2. Передайте Адрес на клиент.
  3. На клиенте вызовите ПолучитьФайл(Адрес, "договор.pdf", Истина) или его асинхронный вариант НачатьПолучениеФайлаССервера.

Пользователю покажется диалог сохранения. Так выгружают файлы и в тонком клиенте, и в веб-клиенте.

Расширение вы подставляете сами. Если записать PDF под именем файл.docx, Word его не откроет. Ориентируйтесь на соседний реквизит «Расширение» или на первые байты содержимого: PDF начинается с %PDF, архив ZIP и документы современного Office — с PK.

Проверка перед записью: размер и пустые значения

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

Если Данные = Неопределено Тогда
    Сообщить("В реквизите нет файла");
    Возврат;
КонецЕсли;

Сообщить("Размер, байт: " + Данные.Размер());

Метод Размер() возвращает число байт. Для ориентира: страница скана в PDF занимает примерно 100-500 КБ, фотография с телефона 2-5 МБ, а нулевой размер означает, что файл не загрузили. Если размер подозрительно мал (десятки байт), внутри, скорее всего, текст ошибки или пустая заглушка, а не документ.

Как открыть сохранённый файл по формату

После записи выберите программу под тип содержимого:

ФорматЧем открыть
PDFлюбой просмотрщик PDF или браузер
DOCX, DOCWord или бесплатный офисный пакет
XLSX, XLSExcel или табличный редактор
JPG, PNGпросмотр изображений
ZIPархиватор, внутри часто несколько файлов
XMLтекстовый редактор или браузер

Если расширение неизвестно, откройте файл в текстовом редакторе. Читаемые теги < и > означают XML или HTML, а набор нечитаемых символов с буквами PK в начале означает архив.

ХранилищеЗначения: сначала достать, потом записать

Реквизит типа ХранилищеЗначения не возвращает данные напрямую. Внутри лежит произвольное значение, и в вашем случае это чаще всего ДвоичныеДанные, но может быть картинка, таблица значений или структура.

Порядок действий:

Значение = Элемент.Хранилище.Получить();

Если ТипЗнч(Значение) = Тип("ДвоичныеДанные") Тогда
    Значение.Записать(ПолучитьИмяВременногоФайла("bin"));
ИначеЕсли ТипЗнч(Значение) = Тип("Картинка") Тогда
    Значение.Записать(ПолучитьИмяВременногоФайла("png"));
КонецЕсли;

Проверка ТипЗнч обязательна. Метод Получить() вернёт Неопределено, если хранилище пустое, и тогда вызов Записать у пустоты упадёт с ошибкой.

Что вернул Получить()Как сохранить
ДвоичныеДанныеЗаписать(Путь)
КартинкаЗаписать(Путь), формат определяется самой картинкой
ТаблицаЗначенийВыгрузить в табличный документ или в файл через XML
НеопределеноДанных нет, проверьте, что запись была заполнена

Если не знаете, что внутри, сначала выведите ТипЗнч(Значение) в сообщение и только потом пишите обработку.

Макеты и ресурсы конфигурации

Макеты с типом «Двоичные данные» хранят шаблоны, библиотеки, внешние компоненты. Из кода их можно получить так:

Макет = ПолучитьОбщийМакет("ИмяМакета");     // общий макет
// или у объекта: Справочники.Товары.ПолучитьМакет("ИмяМакета")
Макет.Записать(ПолучитьИмяВременногоФайла("zip"));

В обоих случаях вернутся двоичные данные, даже если по смыслу это Word-шаблон или архив. Расширение подбираете по назначению макета.

Для разработчика есть и обычный путь: открыть конфигурацию в Конфигураторе, найти макет в дереве объектов и воспользоваться командами сохранения содержимого в файл. Названия пунктов меню зависят от версии платформы, поэтому удобнее ориентироваться на контекстное меню самого макета.

Много файлов сразу: пакетная выгрузка внешней обработкой

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

Скелет цикла:

Запрос = Новый Запрос("ВЫБРАТЬ
    |  Файлы.Ссылка КАК Ссылка,
    |  Файлы.Наименование КАК Имя,
    |  Файлы.Расширение КАК Расширение,
    |  Файлы.ДанныеФайла КАК Данные
    |ИЗ Справочник.МоиФайлы КАК Файлы");

Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    Путь = КаталогВыгрузки + "\" + Выборка.Ссылка.УникальныйИдентификатор() + "." + Выборка.Расширение;
    Выборка.Данные.Записать(Путь);
КонецЦикла;

Имя справочника и реквизитов замените своими. Файлы названы по уникальному идентификатору ссылки: так не будет конфликтов, если у двух документов одинаковое наименование.

Если вложений в базе много, заведите привычку: сначала выгрузите один тестовый файл и откройте его. Убедитесь, что содержимое читается, имя подобрано верно, а кириллица в названии не превратилась в вопросительные знаки. Только после этого запускайте цикл на всю выборку. Такая проверка занимает минуту, а исправлять тысячу неправильно названных файлов придётся часами.

Что учесть до запуска:

  • ⏱ выгрузка тысяч файлов нагружает сервер, запускайте её в нерабочее время;
  • 💾 проверьте свободное место: размер базы вложений может быть в гигабайтах;
  • 🔒 пишите в каталог, куда у процесса есть права записи; на сервере это каталог, доступный пользователю службы 1С;
  • 🧹 имена файлов очищайте от символов \ / : * ? " < > |, иначе запись упадёт.

Обработку удобно запускать в Конфигураторе через открытие .epf и режим отладки, а в обычной работе — через меню внешних обработок, если администратор их разрешил.

Отдать файл по HTTP или принять строку Base64

Если файл нужен внешней системе, его не обязательно записывать на диск. HTTP-сервис вернёт содержимое прямо из базы.

Метод HTTP-сервиса:

Функция ФайлGET(Запрос)
    Ответ = Новый HTTPСервисОтвет(200);
    Ответ.Заголовки.Вставить("Content-Type", "application/pdf");
    Ответ.УстановитьТелоИзДвоичныхДанных(ДанныеФайла);
    Возврат Ответ;
КонецФункции

На стороне другой базы 1С файл забирают так:

Соединение = Новый HTTPСоединение("server.example.ru");
Ответ = Соединение.Получить(Новый HTTPЗапрос("/hs/files/doc1"));
Данные = Ответ.ПолучитьТелоКакДвоичныеДанные();
Данные.Записать(Путь);

Часто вложение приходит текстом в Base64. Преобразование делает пара функций:

  • Base64Значение(Строка) превращает строку в ДвоичныеДанные;
  • Base64Строка(Данные) делает обратное.

В Base64-строке бывают переносы строк, это не ошибка. Но лишние пробелы и префикс вида data:application/pdf;base64, надо отрезать вручную.

HTTP-сервис отдаёт данные любому, у кого есть доступ к публикации. Настройте аутентификацию и ограничьте роли, прежде чем открывать наружу вложения с персональными данными.

Если не помогло: другие способы достать файл

Когда кода писать не хочется или нет прав на внешние обработки, попробуйте обойти проблему:

  1. Попросите автора вложения загрузить файл заново и отправьте его себе другим каналом, например почтой.
  2. Если в базе есть обмен с другой программой, найдите исходный файл там: в системе-источнике он лежит обычным файлом.
  3. Обратитесь к программисту или администратору: у них есть консоль кода и доступ к серверу, они выгрузят файл за пару минут.
  4. Проверьте резервную копию базы на тестовом стенде, если в рабочей базе вложение удалили.

На рабочей базе не экспериментируйте с обработками, которые меняют данные. Для выгрузки достаточно чтения, и любая запись в реквизит должна идти только после копии базы.

Диагностика: выберите симптом

Безопасность: что проверить, прежде чем открывать

Двоичные данные могут оказаться чем угодно, в том числе исполняемым файлом. Правила простые:

  1. Не запускайте файл автоматически, если расширение пришло из внешней системы. Сначала сверьте его со списком разрешённых: pdf, docx, xlsx, jpg, png.
  2. Не записывайте выгрузку в общий каталог, к которому открыт доступ всей сети. Сканы договоров и паспортов содержат персональные данные.
  3. Удаляйте временные файлы после использования: УдалитьФайлы(Путь).
  4. Ограничьте роль, которая может запускать обработки выгрузки: пакетная выгрузка равна копированию всех вложений.
  5. Если файл пришёл по HTTP, проверьте размер до записи. Ответ в несколько гигабайт забьёт диск сервера.

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

Частые вопросы

Можно ли открыть двоичные данные прямо в 1С без записи на диск?
Картинки показываются в форме через поле картинки, если передать ему данные. Для PDF, Word и Excel нужна внешняя программа, значит, файл всё равно записывается во временный каталог.
Чем двоичные данные отличаются от ХранилищеЗначения?
ДвоичныеДанные хранят байты файла. ХранилищеЗначения — контейнер, в который можно положить любое значение, в том числе двоичные данные. Чтобы получить содержимое, у хранилища вызывают Получить().
Как узнать формат файла, если расширение не сохранилось?
Посмотрите первые байты. %PDF означает PDF, PK — ZIP или документ Office нового формата, ÿØ в начале — JPEG. Также помогает соседний реквизит с типом файла.
Почему ПолучитьФайл не работает в веб-клиенте так же, как в толстом?
Браузер сам решает, куда сохранить файл, и показывает диалог загрузки. Автоматически открыть его программой на компьютере нельзя, пользователь делает это вручную.
Как вернуть ДвоичныеДанные из файла на диске?
Создайте объект конструктором: Данные = Новый ДвоичныеДанные(Путь);. После этого данные можно записать в реквизит.