Загрузка файлов в базу 1С из кода: форма, HTTP-сервис, COM и обменная папка

· 10 мин

Содержание

Чтобы программно добавить файл в 1С 8.3, его двоичные данные сначала доставляют на сервер (через временное хранилище, тело HTTP-запроса или параметр внешнего соединения), а затем записывают в реквизит типа ХранилищеЗначения или в справочник присоединённых файлов БСП. Источник файла может быть любым: диалог выбора у пользователя, внешняя система, скрипт на другом компьютере или общая сетевая папка.

Сложность обычно не в самой записи, а в доставке. Клиент и сервер 1С работают на разных машинах, и путь C:\Сканы\акт.pdf с компьютера бухгалтера сервер просто не увидит. Ниже четыре рабочих способа под разные сценарии и код, который можно взять за основу.

Как платформа 1С работает с файлами: клиент, сервер и двоичные данные

В клиент-серверном варианте код с директивой &НаКлиенте видит диск пользователя, а код &НаСервере — диск сервера 1С. Конструктор Новый ДвоичныеДанные(Путь) читает файл там, где он выполняется. Это первое, о чём спотыкаются: на сервере такой вызов ищет файл на сервере.

Основные объекты, которые понадобятся:

  • 📦 ДвоичныеДанные — содержимое файла в памяти. Умеет записываться на диск методом Записать() и считать размер через Размер().
  • 🗄️ ХранилищеЗначения — тип реквизита для хранения данных в базе. Принимает второй параметр Новый СжатиеДанных(9) для сжатия.
  • ⏳ Временное хранилище — механизм передачи данных между клиентом и сервером: ПоместитьВоВременноеХранилище() и ПолучитьИзВременногоХранилища().
  • 📁 Файл — описание файла по пути: свойства Имя, ИмяБезРасширения, Расширение (с точкой), методы Существует() и ЭтоКаталог().
  • 🔤 Base64Строка() и Base64Значение() — превращают двоичные данные в строку и обратно. Нужны там, где канал передаёт только текст.
СпособКогда подходитОграничения
Форма и временное хранилищеПользователь сам выбирает файлНужен открытый клиент 1С
HTTP-сервисФайлы шлёт сайт, скрипт или другая базаНужна публикация на веб-сервере
COM-соединениеСкрипт Windows на машине с установленной платформойТолько Windows, совпадение разрядности
Обменная папкаСканер или внешняя программа кладёт файлы в каталогПрава службы сервера 1С на папку

Добавление файла из формы через временное хранилище

Классическая схема для кнопки «Загрузить файл» на форме. Клиент показывает диалог, платформа передаёт файл на сервер во временное хранилище, а серверная процедура забирает его оттуда и записывает в базу.

Пример ниже работает с собственным справочником ФайлыКонтрагентов. У него реквизиты Владелец (ссылка на контрагента), ИмяФайла (строка), Расширение (строка) и Данные (тип ХранилищеЗначения).

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

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

&НаСервере
Процедура СохранитьФайлНаСервере(Адрес, ПолноеИмя)
    Данные = ПолучитьИзВременногоХранилища(Адрес);
    ОписаниеФайла = Новый Файл(ПолноеИмя);

    Элемент = Справочники.ФайлыКонтрагентов.СоздатьЭлемент();
    Элемент.Владелец = Объект.Ссылка;
    Элемент.Наименование = ОписаниеФайла.ИмяБезРасширения;
    Элемент.ИмяФайла = ОписаниеФайла.Имя;
    Элемент.Расширение = ОписаниеФайла.Расширение;
    Элемент.Данные = Новый ХранилищеЗначения(Данные, Новый СжатиеДанных(9));
    Элемент.Записать();

    УдалитьИзВременногоХранилища(Адрес);
КонецПроцедуры

Три детали, которые часто упускают:

  1. Передавайте УникальныйИдентификатор формы последним параметром. Тогда временное хранилище живёт, пока открыта форма, и данные не пропадут между вызовами.
  2. У нового объекта формы Объект.Ссылка пустая. Сначала запишите карточку контрагента, потом прикрепляйте файлы.
  3. В платформе 8.3.18 и новее появились асинхронные методы ПоместитьФайлНаСерверАсинх() и ПоместитьФайлыНаСерверАсинх(). Схема та же: на сервер приходит адрес во временном хранилище.

Прочитать файл обратно и отдать пользователю так же просто: на сервере Элемент.Данные.Получить() возвращает ДвоичныеДанные, их кладут во временное хранилище, а на клиенте вызывают ПолучитьФайл() или НачатьПолучениеФайлов().

Если в конфигурации есть БСП

В типовых конфигурациях (Бухгалтерия 3.0, ЗУП 3.1, УТ 11) файлы хранятся через подсистему «Работа с файлами» Библиотеки стандартных подсистем. Свой справочник там заводить не нужно: у объектов уже есть справочники присоединённых файлов, например ДоговорыКонтрагентовПрисоединенныеФайлы.

В БСП 3.x файл добавляют серверной функцией РаботаСФайлами.ДобавитьФайл(). Параметры готовят через РаботаСФайлами.ПараметрыДобавленияФайла():

&НаСервере
Функция ПрикрепитьФайлБСП(Владелец, Адрес, ПолноеИмя)
    ОписаниеФайла = Новый Файл(ПолноеИмя);

    ПараметрыФайла = РаботаСФайлами.ПараметрыДобавленияФайла();
    ПараметрыФайла.ВладелецФайлов = Владелец;
    ПараметрыФайла.ИмяБезРасширения = ОписаниеФайла.ИмяБезРасширения;
    ПараметрыФайла.РасширениеБезТочки = Сред(ОписаниеФайла.Расширение, 2);

    Возврат РаботаСФайлами.ДобавитьФайл(ПараметрыФайла, Адрес);
КонецФункции

Плюс БСП в том, что она сама решает, где лежат данные: в базе или в томах на диске. Режим хранения переключается в разделе Администрирование, в настройках работы с файлами. Ваш код от этого не меняется.

Состав полей структуры параметров может различаться между версиями библиотеки. Перед вызовом откройте общий модуль РаботаСФайлами в конфигураторе и сверьте комментарий к функции ПараметрыДобавленияФайла().

Приём файла в 1С через HTTP-сервис

HTTP-сервис нужен, когда файл приходит извне: с сайта, из мобильного приложения, из другой базы или от скрипта на Python. Внешняя сторона отправляет POST-запрос с содержимым файла в теле, 1С сохраняет его и отвечает кодом.

Создание сервиса в конфигураторе

  1. В дереве конфигурации откройте Общие → HTTP-сервисы и добавьте сервис, например Files с корневым URL files.
  2. Добавьте шаблон URL /upload/{name} и в нём метод POST.
  3. В свойствах метода создайте обработчик. Конфигуратор сгенерирует функцию в модуле сервиса.
  4. Опубликуйте базу на веб-сервере (IIS или Apache) с флажком публикации HTTP-сервисов.
  5. Заведите пользователя-робота с ролью, у которой есть права на запись нужных объектов.

Обработчик метода:

Функция UploadPOST(Запрос)
    ИмяФайла = Запрос.ПараметрыURL.Получить("name");
    Данные = Запрос.ПолучитьТелоКакДвоичныеДанные();

    Если Данные = Неопределено Или Данные.Размер() = 0 Тогда
        Ответ = Новый HTTPСервисОтвет(400);
        Ответ.УстановитьТелоИзСтроки("Пустое тело запроса");
        Возврат Ответ;
    КонецЕсли;

    Попытка
        Ссылка = ЗагрузкаФайловСервер.СохранитьВложение(ИмяФайла, Данные);
        Ответ = Новый HTTPСервисОтвет(201);
        Ответ.УстановитьТелоИзСтроки(Строка(Ссылка.УникальныйИдентификатор()));
    Исключение
        ЗаписьЖурналаРегистрации("ЗагрузкаФайлов.HTTP", УровеньЖурналаРегистрации.Ошибка, , ,
            ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
        Ответ = Новый HTTPСервисОтвет(500);
    КонецПопытки;

    Возврат Ответ;
КонецФункции

ЗагрузкаФайловСервер здесь — ваш общий серверный модуль, где лежит запись в справочник (как в процедуре из формы выше). Так один и тот же код сохранения обслуживает все каналы.

Проверить сервис можно утилитой curl с любой машины:

curl -X POST -u Robot:Пароль --data-binary @C:\in\scan.pdf ^
  -H "Content-Type: application/octet-stream" ^
  http://srv-1c/buh/hs/files/upload/scan.pdf

Если файл отправляет другая база 1С, используйте HTTPСоединение. Метод УстановитьИмяФайлаТела() читает тело прямо с диска и не держит весь файл в памяти:

Соединение = Новый HTTPСоединение("srv-1c", 80, "Robot", "Пароль", , 60);
Запрос = Новый HTTPЗапрос("/buh/hs/files/upload/scan.pdf");
Запрос.Заголовки.Вставить("Content-Type", "application/octet-stream");
Запрос.УстановитьИмяФайлаТела("C:\in\scan.pdf");
Ответ = Соединение.ОтправитьДляОбработки(Запрос);

Если Ответ.КодСостояния <> 201 Тогда
    ВызватьИсключение СтрШаблон("Сервис вернул код %1", Ответ.КодСостояния);
КонецЕсли;

IIS по умолчанию ограничивает размер тела запроса примерно 30 МБ (параметр maxAllowedContentLength). Если сканы или архивы крупнее, увеличьте лимит в web.config публикации, иначе запрос отклонит веб-сервер ещё до 1С.

Кириллицу в имени файла внутри URL лучше не передавать: она приходит в URL-кодировке. Либо раскодируйте строку через РаскодироватьСтроку(Имя, СпособКодированияСтроки.КодировкаURL), либо передавайте имя отдельным заголовком.

Загрузка файла через COM-соединение

COM-соединение подходит для скриптов Windows: планировщик заданий запускает PowerShell, тот подключается к базе и передаёт файл. Работает только на машине, где установлена платформа 1С и зарегистрирована библиотека comcntr.dll.

В базе создайте общий модуль с флажками Сервер и Внешнее соединение и экспортной функцией. Файл удобнее передавать строкой Base64: так не нужно, чтобы сервер видел диск скрипта.

Функция ПринятьФайл(ИмяФайла, ДанныеBase64) Экспорт
    Данные = Base64Значение(ДанныеBase64);
    Ссылка = ЗагрузкаФайловСервер.СохранитьВложение(ИмяФайла, Данные);
    Возврат Строка(Ссылка.УникальныйИдентификатор());
КонецФункции

Скрипт PowerShell (модуль назван ЗагрузкаФайловCOM):

$connector = New-Object -ComObject V83.COMConnector
$base = $connector.Connect('Srvr="srv-1c";Ref="buh";Usr="Robot";Pwd="Пароль"')
$bytes = [IO.File]::ReadAllBytes('C:\in\scan.pdf')
$b64 = [Convert]::ToBase64String($bytes)
$id = $base.ЗагрузкаФайловCOM.ПринятьФайл('scan.pdf', $b64)
Write-Output "Загружено: $id"

Для файловой базы строка подключения выглядит так: File="D:\Bases\Buh";Usr="Robot";Pwd="Пароль".

Типичные проблемы COM:

  • 🧩 Недопустимая строка с указанием класса — компонента не зарегистрирована. Выполните от администратора regsvr32 "C:\Program Files\1cv8\<версия>\bin\comcntr.dll".
  • 🔀 Разрядность процесса не совпадает с разрядностью платформы. 64-битный PowerShell не создаст объект 32-битной платформы, и наоборот.
  • 🔄 Версия comcntr.dll должна совпадать с версией сервера 1С. После обновления платформы регистрацию повторяют.
  • 🐘 Base64 увеличивает объём данных примерно на треть. Для файлов в сотни мегабайт COM не лучший канал, берите HTTP-сервис или папку.

Обмен файлами через сетевую папку

Самый простой для внешних систем вариант: сканер или чужая программа кладёт файлы в каталог, а регламентное задание 1С раз в несколько минут забирает их в базу. Никаких веб-серверов и COM.

Процедура ЗагрузитьИзОбменнойПапки() Экспорт
    Каталог = "\\fs01\obmen\vhod\";
    Файлы = НайтиФайлы(Каталог, "*.pdf", Ложь);

    Для Каждого ФайлВПапке Из Файлы Цикл
        Если ФайлВПапке.ЭтоКаталог() Тогда
            Продолжить;
        КонецЕсли;
        Попытка
            Данные = Новый ДвоичныеДанные(ФайлВПапке.ПолноеИмя);
            ЗагрузкаФайловСервер.СохранитьВложение(ФайлВПапке.Имя, Данные);
            ПереместитьФайл(ФайлВПапке.ПолноеИмя, Каталог + "done\" + ФайлВПапке.Имя);
        Исключение
            ЗаписьЖурналаРегистрации("ЗагрузкаФайлов.Папка", УровеньЖурналаРегистрации.Ошибка, , ,
                ФайлВПапке.ПолноеИмя + Символы.ПС + ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
            ПереместитьФайл(ФайлВПапке.ПолноеИмя, Каталог + "error\" + ФайлВПапке.Имя);
        КонецПопытки;
    КонецЦикла;
КонецПроцедуры

Процедуру назначьте методом регламентного задания в Общие → Регламентные задания и задайте расписание. Подкаталоги done и error создайте заранее.

На что смотреть в этом сценарии:

  1. Регламентное задание выполняется на сервере 1С от имени учётной записи службы агента сервера, по умолчанию USR1CV8. Именно ей нужны права на чтение и запись в папку. Права пользователя, который настраивал задание, роли не играют.
  2. Сетевые диски вроде Z:\ служба не видит. Указывайте UNC-путь \\сервер\папка.
  3. Внешняя программа может ещё дописывать файл, когда задание его заберёт. Договоритесь, что запись идёт с временным расширением .tmp, а после завершения файл переименовывают. Маска *.pdf тогда пропустит недописанное.
  4. Перемещайте обработанные файлы, а не удаляйте сразу. Папка done служит страховкой на случай ошибки в коде записи.

Где хранить вложения: в базе или на диске

Хранение в ХранилищеЗначения надёжно: файлы попадают в резервную копию вместе с базой, их не потеряешь при переносе. Цена — рост размера базы и выгрузки .dt.

ВариантПлюсыМинусы
Реквизит ХранилищеЗначения в объектеОдин объект, просто читатьТяжёлый объект грузится целиком при открытии формы
Отдельный справочник с хранилищемДокумент открывается быстро, файлы грузятся по запросуНужна своя форма списка
Тома на диске (БСП)База не растёт, тяжёлые архивы не мешаютПапки томов нужно бэкапить отдельно

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

Новый СжатиеДанных(9) даёт максимальное сжатие. Для PDF и JPEG выигрыш небольшой, они уже сжаты. Для XML, текстов и выгрузок Excel старого формата разница бывает в разы.

Обработка ошибок и журнал загрузки

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

Что писать в журнал регистрации:

  • 🏷️ Имя события с префиксом подсистемы, например ЗагрузкаФайлов.HTTP. По нему потом фильтруют журнал.
  • 📝 Имя или путь файла и ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()). Краткое представление теряет стек вызовов.
  • ✅ Успешные загрузки — с уровнем УровеньЖурналаРегистрации.Информация и ссылкой на созданный объект в параметре данных.

Журнал открывают в пользовательском режиме через Администрирование → Обслуживание → Журнал регистрации (в Бухгалтерии 3.0) или в конфигураторе через Администрирование → Журнал регистрации. Отбор по имени события сразу показывает все сбои загрузки.

Перед записью стоит проверить входные данные:

  1. Размер. Ограничьте максимум, например 20 МБ, и отклоняйте больше: Если Данные.Размер() > 20 * 1024 * 1024 Тогда.
  2. Расширение. Разрешите список (.pdf, .jpg, .png, .xml) и отбрасывайте исполняемые файлы.
  3. Дубли. Если внешняя система может прислать файл дважды, храните хеш. Объект ХешированиеДанных с типом ХешФункция.SHA256 считает его по двоичным данным, а поиск по реквизиту с хешем отсекает повторы.
Диагностика: выберите симптом

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

Можно ли записать файл в базу 1С без формы и пользователя?
Да. Регламентное задание, HTTP-сервис и COM-соединение работают без интерактивного сеанса. Нужен только пользователь-робот с правами на запись объектов.
Как программно выгрузить файл из базы обратно на диск?
На сервере получите ДвоичныеДанные методом Получить() у хранилища и вызовите Данные.Записать("\\fs01\out\имя.pdf"). Путь должен быть доступен серверу 1С.
Почему после загрузки файлов база сильно выросла?
Каждый файл в ХранилищеЗначения хранится внутри базы. Включите сжатие, вынесите файлы в отдельный справочник или переведите хранение БСП в тома на диске.
Работает ли загрузка через форму в веб-клиенте?
Да, НачатьПомещениеФайла() и асинхронные методы помещения работают и в тонком, и в веб-клиенте. Синхронный ПоместитьФайл() в веб-клиенте использовать нельзя.
Как передать несколько файлов одним действием?
В форме используйте НачатьПомещениеФайлов() или ПоместитьФайлыНаСерверАсинх(). Во внешней интеграции проще отправлять файлы отдельными запросами: сбой одного не сорвёт остальные.