Файл лежит в базе 1С как двоичные данные: как достать и открыть
Содержание
Пользователь прислал скан договора, а в карточке контрагента вместо файла видна строка «Двоичные данные». Или в консоли запросов в колонке стоит ДвоичныеДанные и ничего не открывается. Это нормально: 1С не показывает содержимое двоичных данных, их нужно сначала записать в файл на диск, а потом открыть программой, которая понимает формат.
Короткий путь такой: получить значение типа ДвоичныеДанные, вызвать у него метод Записать(ИмяФайла) и открыть получившийся файл. Всё остальное зависит от того, где именно лежат данные: в реквизите, в ХранилищеЗначения, в макете или на стороне другой системы.
Что такое двоичные данные и где они прячутся
Тип ДвоичныеДанные хранит набор байт без указания формата. Расширение файла, имя и тип содержимого в нём не записаны. Поэтому имя и расширение вы задаёте сами или берёте из соседнего реквизита.
Чаще всего двоичные данные встречаются в таких местах:
- 📎 присоединённые файлы документов и справочников (скан, PDF, картинка);
- 🗄 реквизиты типа
ХранилищеЗначения, куда программисты кладут вложения; - 📄 макеты конфигурации с типом «Двоичные данные»;
- 🌐 ответы внешних сервисов и содержимое писем;
- 🔤 строки в формате Base64, которые пришли из обмена.
Если вы видите в списке слово «Хранилище» или «Двоичные данные» вместо имени файла, значит, содержимое надо извлекать кодом или штатной кнопкой формы. Узнайте у разработчика, как называется реквизит, прежде чем писать код: это сэкономит час поисков.
Если в форме есть кнопка: открываем без кода
Присоединённые файлы в типовых конфигурациях открываются штатно. Откройте документ или карточку, найдите ссылку «Файлы» или значок скрепки, выберите файл и нажмите «Открыть» либо «Сохранить как». 1С сама запишет данные во временный каталог и запустит нужную программу.
Если кнопки нет, а файл в базе точно есть, проверьте права: у роли может быть закрыто чтение присоединённых файлов. Это решается правами, а не кодом.
Перед выгрузкой убедитесь, что файл нужен целиком. Для просмотра вложения часто хватает штатного просмотра внутри 1С, а запись на диск понадобится только для передачи другому человеку.
Запись двоичных данных на диск встроенным языком
Это универсальный способ. Подходит для внешней обработки, расширения и консоли кода.
Предположим, у вас есть ссылка на элемент справочника с реквизитом ДанныеФайла типа ДвоичныеДанные:
Данные = Элемент.ДанныеФайла; // значение типа ДвоичныеДанные
Путь = ПолучитьИмяВременногоФайла("pdf");
Данные.Записать(Путь);
Функция ПолучитьИмяВременногоФайла возвращает уникальный путь во временном каталоге пользователя, расширение вы передаёте строкой без точки. Файл не затрётся при повторном запуске.
Чтобы сразу открыть результат на клиенте, добавьте:
НачатьЗапускПриложения(Новый ОписаниеОповещения("ПослеЗапуска", ЭтотОбъект), Путь);
В старых формах встречается синхронный ЗапуститьПриложение(Путь). Оно работает в толстом клиенте, а в веб-клиенте часть таких вызовов недоступна.
Что делать на сервере, если пользователь работает на клиенте
Клиент и сервер видят разные файловые системы. Записать файл в C:\Temp на сервере бесполезно: у пользователя его не будет. Правильная цепочка такая:
- На сервере положите данные во временное хранилище:
Адрес = ПоместитьВоВременноеХранилище(Данные, УникальныйИдентификатор); - Передайте
Адресна клиент. - На клиенте вызовите
ПолучитьФайл(Адрес, "договор.pdf", Истина)или его асинхронный вариантНачатьПолучениеФайлаССервера.
Пользователю покажется диалог сохранения. Так выгружают файлы и в тонком клиенте, и в веб-клиенте.
Расширение вы подставляете сами. Если записать PDF под именем файл.docx, Word его не откроет. Ориентируйтесь на соседний реквизит «Расширение» или на первые байты содержимого: PDF начинается с %PDF, архив ZIP и документы современного Office — с PK.
Проверка перед записью: размер и пустые значения
Прежде чем писать файл, убедитесь, что данные вообще есть. Пустая ссылка или незаполненный реквизит дают Неопределено, и вызов Записать падает с ошибкой.
Если Данные = Неопределено Тогда
Сообщить("В реквизите нет файла");
Возврат;
КонецЕсли;
Сообщить("Размер, байт: " + Данные.Размер());
Метод Размер() возвращает число байт. Для ориентира: страница скана в PDF занимает примерно 100-500 КБ, фотография с телефона 2-5 МБ, а нулевой размер означает, что файл не загрузили. Если размер подозрительно мал (десятки байт), внутри, скорее всего, текст ошибки или пустая заглушка, а не документ.
Как открыть сохранённый файл по формату
После записи выберите программу под тип содержимого:
| Формат | Чем открыть |
|---|---|
| любой просмотрщик PDF или браузер | |
| DOCX, DOC | Word или бесплатный офисный пакет |
| XLSX, XLS | Excel или табличный редактор |
| 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-сервис отдаёт данные любому, у кого есть доступ к публикации. Настройте аутентификацию и ограничьте роли, прежде чем открывать наружу вложения с персональными данными.
Если не помогло: другие способы достать файл
Когда кода писать не хочется или нет прав на внешние обработки, попробуйте обойти проблему:
- Попросите автора вложения загрузить файл заново и отправьте его себе другим каналом, например почтой.
- Если в базе есть обмен с другой программой, найдите исходный файл там: в системе-источнике он лежит обычным файлом.
- Обратитесь к программисту или администратору: у них есть консоль кода и доступ к серверу, они выгрузят файл за пару минут.
- Проверьте резервную копию базы на тестовом стенде, если в рабочей базе вложение удалили.
На рабочей базе не экспериментируйте с обработками, которые меняют данные. Для выгрузки достаточно чтения, и любая запись в реквизит должна идти только после копии базы.
%PDF для PDF, PK для ZIP и docx. Если пришла строка, пропустите её через Base64Значение.ДвоичныеДанные, а ХранилищеЗначения или Неопределено. Вызовите Получить() и проверьте ТипЗнч.ПоместитьВоВременноеХранилище и заберите на клиенте функцией ПолучитьФайл.Безопасность: что проверить, прежде чем открывать
Двоичные данные могут оказаться чем угодно, в том числе исполняемым файлом. Правила простые:
- Не запускайте файл автоматически, если расширение пришло из внешней системы. Сначала сверьте его со списком разрешённых:
pdf,docx,xlsx,jpg,png. - Не записывайте выгрузку в общий каталог, к которому открыт доступ всей сети. Сканы договоров и паспортов содержат персональные данные.
- Удаляйте временные файлы после использования:
УдалитьФайлы(Путь). - Ограничьте роль, которая может запускать обработки выгрузки: пакетная выгрузка равна копированию всех вложений.
- Если файл пришёл по HTTP, проверьте размер до записи. Ответ в несколько гигабайт забьёт диск сервера.
Не отключайте проверку расширений ради удобства. Так в базу попадают файлы, которые потом открывает бухгалтер двойным щелчком.
Частые вопросы
Можно ли открыть двоичные данные прямо в 1С без записи на диск?
Чем двоичные данные отличаются от ХранилищеЗначения?
ДвоичныеДанные хранят байты файла. ХранилищеЗначения — контейнер, в который можно положить любое значение, в том числе двоичные данные. Чтобы получить содержимое, у хранилища вызывают Получить().Как узнать формат файла, если расширение не сохранилось?
%PDF означает PDF, PK — ZIP или документ Office нового формата, ÿØ в начале — JPEG. Также помогает соседний реквизит с типом файла.Почему ПолучитьФайл не работает в веб-клиенте так же, как в толстом?
Как вернуть ДвоичныеДанные из файла на диске?
Данные = Новый ДвоичныеДанные(Путь);. После этого данные можно записать в реквизит.