Загрузка файла пользователя на сервер 1С через временное хранилище

· 10 мин

Содержание

Чтобы передать файл с клиента на сервер в 1С 8.3, его помещают во временное хранилище методом НачатьПомещениеФайлаНаСервер (платформа 8.3.13 и выше) или НачатьПомещениеФайла. Клиент получает адрес, передаёт его в серверную процедуру, а сервер достаёт ДвоичныеДанные через ПолучитьИзВременногоХранилища и пишет их на диск или в реквизит.

Прямого «копирования» с компьютера пользователя на сервер в 1С нет. Клиент и сервер — разные процессы, часто на разных машинах, и общаются только через вызовы сервера. Поэтому любая загрузка идёт в два хода: клиент отдаёт данные платформе, сервер забирает их по адресу.

Почему файл нельзя просто открыть по пути на сервере

Частая ошибка новичка — передать на сервер строку C:\Users\Ivanov\Desktop\price.xlsx и попытаться прочитать её там. В клиент-серверном варианте сервер ищет этот путь у себя, на диске сервера 1С. Файла там нет, и вы получаете ошибку доступа или «файл не найден».

Что нужно держать в голове:

  • 🖥️ Код &НаКлиенте видит файловую систему компьютера пользователя (в веб-клиенте — только через диалог или расширение работы с файлами).
  • 🗄️ Код &НаСервере работает в рабочем процессе rphost и видит только диски сервера и сетевые ресурсы, доступные учётной записи службы.
  • 📦 Мост между ними — временное хранилище. Клиент кладёт туда двоичные данные, сервер забирает по адресу-строке.
  • 💾 Файловый вариант базы ведёт себя иначе: «сервер» выполняется на той же машине, поэтому ошибка с путями маскируется. Код, написанный и проверенный на файловой базе, ломается при переходе на сервер. Тестируйте сразу в клиент-серверном режиме.

Какой способ выбрать

СпособПлатформаКогда подходитОграничения
НачатьПомещениеФайлаНаСервер8.3.13+Новые разработки, нужен прогресс и отменаНе работает на старых платформах
ПоместитьФайлНаСерверАсинх + Ждать8.3.18+Тот же метод, но код читается линейноПроцедура должна быть Асинх
НачатьПомещениеФайла8.3Совместимость со старыми релизамиНет прогресса, без расширения в веб-клиенте только диалог
НачатьПомещениеФайлов8.3Несколько файлов за разТо же, что выше
ПоместитьФайл8.3Только старые конфигурации с модальностьюСинхронный, при запрете модальности вызывает ошибку
Новый ДвоичныеДанные(Путь) на клиенте + параметр серверной процедуры8.3Тонкий клиент, путь известен, файл небольшойНе работает в веб-клиенте, весь файл идёт одним вызовом

Если конфигурация собрана в режиме совместимости ниже 8.3.13, новые методы будут недоступны даже на свежей платформе. Режим смотрят в свойствах корня конфигурации, свойство «Режим совместимости».

Шаг 1. Выбор и чтение файла на клиенте

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

&НаКлиенте
Процедура ЗагрузитьФайл(Команда)

	ПараметрыДиалога = Новый ПараметрыДиалогаПомещенияФайлов;
	ПараметрыДиалога.Заголовок = "Выберите файл для загрузки";
	ПараметрыДиалога.Фильтр = "Таблицы Excel (*.xlsx)|*.xlsx|Все файлы (*.*)|*.*";

	Оповещение = Новый ОписаниеОповещения("ЗагрузитьФайлЗавершение", ЭтотОбъект);

	НачатьПомещениеФайлаНаСервер(Оповещение, , , , ПараметрыДиалога, УникальныйИдентификатор);

КонецПроцедуры

Пустые параметры между оповещением и параметрами диалога — это оповещение о ходе выполнения, оповещение перед началом и адрес хранилища. Адрес можно не указывать: платформа создаст новый.

Последний параметр — УникальныйИдентификатор формы. Передавайте его всегда. Тогда данные живут во временном хранилище, пока открыта форма. Без идентификатора платформа может удалить значение раньше, чем до него дойдёт серверный код.

Обработчик завершения

&НаКлиенте
Процедура ЗагрузитьФайлЗавершение(ОписаниеФайла, ДополнительныеПараметры) Экспорт

	Если ОписаниеФайла = Неопределено
		Или ОписаниеФайла.ПомещениеФайлаОтменено Тогда
		Возврат;
	КонецЕсли;

	ИмяФайла = ОписаниеФайла.СсылкаНаФайл.Имя;
	ЗаписатьФайлНаСервере(ОписаниеФайла.Адрес, ИмяФайла);

КонецПроцедуры

Процедура-обработчик обязательно Экспорт, иначе ОписаниеОповещения её не вызовет. Объект ОписаниеПомещенногоФайла содержит адрес во временном хранилище, признак отмены и ссылку на файл, из которой берут имя.

Тот же код через Асинх и Ждать

На платформе 8.3.18 и выше обработчик можно убрать:

&НаКлиенте
Асинх Процедура ЗагрузитьФайлАсинх(Команда)

	ПараметрыДиалога = Новый ПараметрыДиалогаПомещенияФайлов;
	ПараметрыДиалога.Заголовок = "Выберите файл для загрузки";

	ОписаниеФайла = Ждать ПоместитьФайлНаСерверАсинх(, , , ПараметрыДиалога, УникальныйИдентификатор);

	Если ОписаниеФайла = Неопределено
		Или ОписаниеФайла.ПомещениеФайлаОтменено Тогда
		Возврат;
	КонецЕсли;

	ЗаписатьФайлНаСервере(ОписаниеФайла.Адрес, ОписаниеФайла.СсылкаНаФайл.Имя);

КонецПроцедуры

Файл с известным путём, без диалога

Если путь уже известен (например, обработка забирает выгрузку из C:\Exchange\out.xml), диалог не нужен. Используйте НачатьПомещениеФайла с параметром Интерактивно = Ложь:

&НаКлиенте
Процедура ЗагрузитьВыгрузку(Команда)

	Оповещение = Новый ОписаниеОповещения("ЗагрузитьВыгрузкуЗавершение", ЭтотОбъект);
	НачатьПомещениеФайла(Оповещение, , "C:\Exchange\out.xml", Ложь, УникальныйИдентификатор);

КонецПроцедуры

&НаКлиенте
Процедура ЗагрузитьВыгрузкуЗавершение(Результат, Адрес, ВыбранноеИмяФайла, ДополнительныеПараметры) Экспорт

	Если Не Результат Тогда
		Сообщить("Файл не передан: " + ВыбранноеИмяФайла);
		Возврат;
	КонецЕсли;

	ЗаписатьФайлНаСервере(Адрес, "out.xml");

КонецПроцедуры

В веб-клиенте неинтерактивное помещение требует установленного расширения работы с файлами. Об этом — в разделе про веб-клиент.

Шаг 2. Передача адреса в серверный контекст

Через вызов сервера передают адрес (строку), а не сами данные. Это главное правило для форм.

Почему не стоит передавать ДвоичныеДанные параметром:

  • 📉 При вызове &НаСервере из формы на сервер уходят и данные формы. Тяжёлый параметр плюс большая форма — заметная задержка.
  • 🔁 Данные в хранилище уже лежат на сервере. Передавая их параметром, вы гоните файл по сети второй раз.
  • 🧩 Адрес можно отдать в фоновое задание или общий модуль — там нет формы, но хранилище доступно.

Если серверная процедура не трогает реквизиты формы, объявляйте её &НаСервереБезКонтекста. Тогда данные формы на сервер не передаются вообще:

&НаСервереБезКонтекста
Процедура ЗаписатьФайлНаСервере(Адрес, ИмяФайла)
	// код записи — в следующем разделе
КонецПроцедуры

Для обработки длинных файлов (загрузка прайса на 50 000 строк) запускайте разбор в фоновом задании и передавайте ему адрес. Пользователь не ждёт с замороженной формой, а сервер не упирается в таймаут веб-сервера.

Шаг 3. Запись файла на сервере: каталог, реквизит или присоединённый файл

На сервере данные достают одной строкой и дальше решают, куда их положить.

Запись в каталог на диске сервера

&НаСервереБезКонтекста
Процедура ЗаписатьФайлНаСервере(Адрес, ИмяФайла)

	ДвоичныеДанныеФайла = ПолучитьИзВременногоХранилища(Адрес);
	Если ТипЗнч(ДвоичныеДанныеФайла) <> Тип("ДвоичныеДанные") Тогда
		ВызватьИсключение "Данные файла не найдены во временном хранилище";
	КонецЕсли;

	БезопасноеИмя = СтрЗаменить(ИмяФайла, "\", "_");
	БезопасноеИмя = СтрЗаменить(БезопасноеИмя, "/", "_");
	БезопасноеИмя = СтрЗаменить(БезопасноеИмя, "..", "_");

	Каталог = "D:\1C_Files\Incoming\";
	ПолноеИмя = Каталог + Строка(Новый УникальныйИдентификатор) + "_" + БезопасноеИмя;

	ДвоичныеДанныеФайла.Записать(ПолноеИмя);
	УдалитьИзВременногоХранилища(Адрес);

КонецПроцедуры

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

  1. Имя файла от пользователя нельзя писать как есть. Строка вида ..\..\config.ini выведет запись за пределы каталога. Чистите разделители и ...
  2. Уникальный префикс защищает от перезаписи, когда два пользователя загружают Прайс.xlsx одновременно.
  3. УдалитьИзВременногоХранилища освобождает память рабочего процесса сразу, не дожидаясь закрытия формы.

Сетевая папка и права службы

Если каталог — сетевой ресурс \\fileserver\1c$\incoming, запись выполняет не пользователь, а учётная запись службы сервера 1С. По умолчанию это локальная учётная запись USR1CV8, и у неё нет прав на чужие сетевые ресурсы.

Варианты решения:

  • 🔑 запустить службу «Агент сервера 1С:Предприятия 8.3» от доменной учётной записи и дать ей права на запись в папку;
  • 📁 писать в локальный каталог сервера, а дальше раскладывать файлы штатными средствами ОС.

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

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

Хранение в реквизите базы

Чтобы файл ехал вместе с базой в выгрузке .dt и не зависел от дисков, кладите его в реквизит типа ХранилищеЗначения:

ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();
ДокументОбъект.ФайлВложения = Новый ХранилищеЗначения(ДвоичныеДанныеФайла, Новый СжатиеДанных(9));
ДокументОбъект.Записать();

Читают обратно через ДокументОбъект.ФайлВложения.Получить(). Сжатие уровня 9 хорошо жмёт XML и текст, а для PDF, JPEG и ZIP почти ничего не даёт.

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

Какое хранилище выбрать

КудаПлюсыМинусы
Каталог на сервереБаза не растёт, файлы видны другим программамНужны права службы, файлы не попадают в .dt
ХранилищеЗначения в реквизитеВсё в одной базе, транзакционноБаза растёт, выгрузка .dt тяжелеет
Присоединённые файлы БСПВерсии, тома, готовый интерфейсТолько в конфигурациях на БСП

Как обработать ошибки при передаче файла

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

На сервере оборачивайте запись в Попытка и пишите подробности в журнал регистрации, а пользователю отдавайте короткий текст:

&НаСервереБезКонтекста
Функция ЗаписатьФайлБезопасно(Адрес, ПолноеИмя)

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

КонецФункции

Пустая строка на выходе значит успех, непустая — текст для Сообщить на клиенте. Каталог заранее проверяйте через Новый Файл(Каталог).Существует() и создавайте СоздатьКаталог(Каталог), если его нет.

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

Передача файла на сервер в веб-клиенте и мобильном приложении

Браузер не даёт сайту читать диск пользователя без его участия. Поэтому в веб-клиенте 1С:

  • ✅ Интерактивный выбор (диалог «Открыть файл») работает без расширения во всех поддерживаемых браузерах.
  • ⛔ Помещение по известному пути (Интерактивно = Ложь) требует расширения работы с файлами.
  • ⛔ Новый ДвоичныеДанные(Путь) на клиенте в веб-клиенте недоступен.

Проверка и подключение расширения:

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

&НаКлиенте
Процедура ПодготовитьРасширениеЗавершение(Подключено, ДополнительныеПараметры) Экспорт
	Если Не Подключено Тогда
		НачатьУстановкуРасширенияРаботыСФайлами();
	КонецЕсли;
КонецПроцедуры

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

Пишите код так, чтобы он работал одинаково в тонком и веб-клиенте: асинхронные методы, диалог по умолчанию, неинтерактивный вариант — как опция. Тогда не придётся держать две ветки через #Если ВебКлиент Тогда.

В мобильном приложении и мобильном клиенте асинхронные методы помещения файлов тоже работают. Диалог выбора файла показывает системный выбор документа, фото или файла из облака. Произвольный путь вида C:\... там бессмыслен: доступ к файловой системе устройства ограничен песочницей приложения.

Большие файлы: как передать без зависаний и обрывов

Файл в несколько мегабайт уходит без вопросов. Проблемы начинаются с десятков и сотен мегабайт.

Что ограничивает размер

  • 🌐 Веб-сервер публикации. В Apache и IIS свои лимиты на размер тела запроса и таймауты. Если перед публикацией стоит nginx, проверьте client_max_body_size.
  • 🧠 Память рабочего процесса. ДвоичныеДанные целиком лежат в памяти rphost. Десять пользователей с файлами по 500 МБ — это пять гигабайт.
  • ⏱️ Время вызова. Длинная синхронная обработка на сервере держит соединение и может упереться в таймаут.

Приёмы

  1. Используйте НачатьПомещениеФайлаНаСервер с оповещением о ходе выполнения. Пользователь видит прогресс и может отменить загрузку, а не закрывает «зависшее» окно.
  2. Режьте файл на части. Глобальная функция РазделитьФайл(ИмяФайла, РазмерЧасти) возвращает массив имён частей. Передайте части по очереди, на сервере соберите их ОбъединитьФайлы(МассивИмён, ИмяРезультата).
  3. Сжимайте текстовые файлы. XML и CSV в ZIP-архиве (ЗаписьZipФайла) уменьшаются в разы, на сервере архив распаковывают через ЧтениеZipФайла.
  4. Сразу пишите на диск и удаляйте из хранилища. Не держите сотни мегабайт во временном хранилище до закрытия формы.
  5. Разбор — в фоне. Сервер сохранил файл, фоновое задание его обработало, форма показала результат.

Пример оповещения о ходе выполнения:

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

Его передают вторым параметром: НачатьПомещениеФайлаНаСервер(Оповещение, Новый ОписаниеОповещения("ХодЗагрузки", ЭтотОбъект), , , ПараметрыДиалога, УникальныйИдентификатор). Если не уверены в составе параметров обработчика на вашей платформе, сверьтесь с синтакс-помощником по методу.

Если файл — регулярный обмен большого объёма между системами, а не ручная загрузка, файлы лучше класть в общую папку обмена, откуда их забирает регламентное задание. Ручная загрузка через форму для этого не предназначена.

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

Можно ли передать на сервер сразу несколько файлов?
Да. Используйте НачатьПомещениеФайлов или включите множественный выбор в параметрах диалога. Обработчик получит массив описаний, у каждого свой адрес во временном хранилище.
Где физически лежат данные временного хранилища?
На сервере 1С, в памяти и временных файлах рабочего процесса. Это не постоянное хранилище: после закрытия формы или завершения сеанса данные удаляются.
Как вернуть файл с сервера обратно пользователю?
Обратный путь симметричный: на сервере поместите двоичные данные во временное хранилище, на клиенте вызовите НачатьПолучениеФайлаССервера или ПолучитьФайл с этим адресом.
Работает ли этот код в файловой базе?
Да, без изменений. В файловом варианте серверный код выполняется на компьютере пользователя, но временное хранилище и методы помещения работают так же.
Нужно ли передавать файл на сервер, если его надо только прочитать?
Если разбор идёт на клиенте и данные не нужны серверу, передавать не нужно. Но в веб-клиенте читать файл на клиенте сложнее, поэтому обычно проще поместить его на сервер и разобрать там.