Перенос присоединенных файлов между различными информационными базами 1С — одна из наиболее частых задач при построении интеграционных решений. На первый взгляд алгоритм выглядит просто: выгрузить файл во временный каталог на стороне отправителя, передать по каналам связи и загрузить в справочник присоединенных файлов на стороне получателя. Однако на практике разработчики регулярно сталкиваются с неочевидными системными ошибками, такими как «Отказано в доступе (0x00000005)», повреждением структуры файлов при передаче, а также сбоями при попытке прикрепить файл к документам БСП (Библиотеки Стандартных Подсистем). Для решения подобных интеграционных задач можно использовать готовый инструмент для обмена файлами и данными между базами 1С.
В этой статье мы подробно разберем все этапы реализации надежного обмена файлами, выясним причины возникновения системных ошибок файловой системы и напишем готовый к использованию код для передачи данных через веб-сервисы и JSON-пакеты.
---
Рассмотрим ситуацию, с которой часто сталкиваются начинающие разработчики. При попытке сохранить двоичные данные из хранилища значений на диск с помощью кода:
Путь = "D:\NewFile";
Хранилище = Выборка.ФайлХранилище.Получить();
Хранилище.Записать(Путь);
Система возвращает ошибку: «Ошибка доступа к файлу... 5(0x00000005): Отказано в доступе». Проанализируем причины этой проблемы. Их две:
Записать() объекта ДвоичныеДанные (или ХранилищеЗначения) ожидает получить полный путь к конечному файлу, включая его имя и расширение (например, "D:\NewFile\contract.pdf"). Если указать только путь к каталогу, операционная система заблокирует операцию записи, выдав ошибку доступа.USR1CV8 или NetworkService). По умолчанию у этих пользователей нет прав на запись в корень дисков (например, D:\) или в личные папки пользователей Windows.Как правильно работать с временными путями в 1С:
Для гарантированного обхода проблем с правами доступа никогда не следует жестко прописывать пути к дискам или сетевым папкам в коде. Платформа 1С предоставляет встроенные механизмы работы с временными файлами. Метод ПолучитьИмяВременногоФайла() автоматически генерирует уникальное имя файла и помещает его в системную временную папку сервера (или локального ПК, если код выполняется на клиенте). К этой папке у службы сервера 1С всегда есть полные права на чтение и запись.
Посмотрим на пример правильного извлечения файла во временный каталог:
// Получаем расширение оригинального файла (например, "pdf" или "docx")
Расширение = Выборка.РасширениеФайла;
// Генерируем безопасный путь во временном каталоге сервера
ПутьКВременномуФайлу = ПолучитьИмяВременногоФайла(Расширение);
// Извлекаем двоичные данные из хранилища значений
ДвоичныеДанныеФайла = Выборка.ФайлХранилище.Получить();
Если ТипЗнч(ДвоичныеДанныеФайла) = Тип("ДвоичныеДанные") Тогда
// Записываем файл на диск по безопасному пути
ДвоичныеДанныеФайла.Записать(ПутьКВременномуФайлу);
ИначеЕсли ТипЗнч(ДвоичныеДанныеФайла) = Тип("ХранилищеЗначения") Тогда
ДвоичныеДанныеФайла.Получить().Записать(ПутьКВременномуФайлу);
КонецЕсли;
---
Передать бинарный файл «как есть» напрямую внутри текстового формата JSON невозможно. Для этого бинарные данные необходимо закодировать в текстовую строку. Стандартом для таких операций является кодирование в **Base64**.
Выясним, как выглядит процесс передачи файла «База-Отправитель -> JSON -> База-Получатель»:
Нам необходимо считать файл с диска в объект ДвоичныеДанные, перевести его в формат Base64 и упаковать в структуру JSON для последующей передачи через HTTP-запрос или веб-сервис.
Функция СформироватьПакетДанныхФайла(ПутьКФайлу, ИмяФайла, Расширение) Экспорт
// Читаем файл в двоичные данные
ФайлДД = Новый ДвоичныеДанные(ПутьКФайлу);
// Кодируем двоичные данные в текстовую строку Base64
СтрокаBase64 = Base64Строка(ФайлДД);
// Формируем структуру для сериализации в JSON
СтруктураПакета = Новый Структура;
СтруктураПакета.Вставить("ИмяФайла", ИмяФайла);
СтруктураПакета.Вставить("Расширение", Расширение);
СтруктураПакета.Вставить("ДанныеФайластрокой", СтрокаBase64);
// Записываем структуру в JSON
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, СтруктураПакета);
Возврат ЗаписьJSON.Закрыть();
КонецФункции
Когда база-получатель принимает JSON-пакет, она должна выполнить обратное преобразование: прочитать строку Base64 и преобразовать ее в объект ДвоичныеДанные.
Процедура ПринятьИСохранитьФайлИзJSON(СтрокаJSON) Экспорт
// Читаем входящий JSON-пакет
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
ДанныеПакета = ПрочитатьJSON(ЧтениеJSON);
ЧтениеJSON.Закрыть();
ИмяФайла = ДанныеПакета.ИмяФайла;
Расширение = ДанныеПакета.Расширение;
СтрокаBase64 = ДанныеПакета.ДанныеФайластрокой;
// Декодируем строку Base64 обратно в двоичные данные
ДвоичныеДанныеФайла = Base64Значение(СтрокаBase64);
// Теперь у нас есть чистый объект ДвоичныеДанные, готовый к записи
ПутьДляСохранения = ПолучитьИмяВременногоФайла(Расширение);
ДвоичныеДанныеФайла.Записать(ПутьДляСохранения);
// Дальнейшая логика прикрепления файла к объекту базы...
КонецПроцедуры
Важное предупреждение по производительности: Кодирование файлов в Base64 увеличивает размер передаваемых данных примерно на 33%. Если вам необходимо передавать файлы размером более 50-100 МБ, рекомендуется использовать прямую передачу бинарных потоков через HTTP-сервисы (заголовки Content-Type: application/octet-stream) без кодирования в текст.
---
Разберем типичную ошибку архитектуры, упомянутую в обсуждении. Попытка записать двоичные данные напрямую в реквизит ХранилищеДанных справочника присоединенных файлов (например, Справочник.ДокументыПрисоединенныеФайлы) часто приводит к тому, что файлы перестают открываться пользователями или вызывают критические ошибки системы.
Почему прямая запись в реквизит недопустима в БСП?
Современные конфигурации 1С (ERP, КА, УТ, БП, ЗУП) используют стандартные механизмы подсистемы «Работа с файлами». В зависимости от настроек программы, файлы могут храниться:
Если в системе включено хранение файлов в томах на диске, прямая запись данных в реквизит ХранилищеДанных приведет к нарушению целостности системы. Справочник создаст карточку файла, но самого физического файла на диске не окажется. Кроме того, при ручном создании элемента справочника не регистрируются обязательные метаданные: размер файла, его автор, расширение, статус проверки на вирусы и хэш-сумма.
Чтобы избежать подобных проблем, используйте программный интерфейс БСП — общий модуль РаботаСФайлами. Рассмотрим пошаговый алгоритм добавления полученного файла к документу-приемнику:
Процедура ПрикрепитьФайлКДокументуБСП(ДвоичныеДанныеФайла, СсылкаНаДокумент, ИмяФайла, Расширение)
// Шаг 1. Помещаем двоичные данные во временное хранилище 1С
АдресВременногоХранилища = ПоместитьВоВременноеХранилище(ДвоичныеДанныеФайла);
// Шаг 2. Инициализируем структуру параметров для добавления файла через БСП
ПараметрыФайла = РаботаСФайлами.ПараметрыДобавленияФайла();
ПараметрыФайла.Автор = Пользователи.ТекущийПользователь();
// Указываем владельца файла (документ, справочник или бизнес-процесс)
ПараметрыФайла.ВладелецФайлов = СсылкаНаДокумент;
// Настраиваем имя и расширение
ПараметрыФайла.ИмяБезРасширения = ИмяФайла;
ПараметрыФайла.РасширениеБезТочки = Расширение;
// Шаг 3. Вызываем стандартную процедуру БСП для автоматического создания элемента
// Она сама определит, куда положить файл (в базу или на том), посчитает размер и свяжет с документом
РезультатДобавления = РаботаСФайлами.ДобавитьФайл(ПараметрыФайла, АдресВременногоХранилища);
Если РезультатДобавления.ФайлДобавлен Тогда
ЗаписатьЛогСобытия("Файл успешно прикреплен к документу: " + Строка(СсылкаНаДокумент));
Иначе
ВызватьИсключение "Не удалось прикрепить файл средствами БСП: " + РезультатДобавления.ТекстОшибки;
КонецЕсли;
КонецПроцедуры
---
Для создания отказоустойчивого механизма обмена файлами между базами 1С всегда следуйте этим правилам:
ПолучитьИмяВременногоФайла().Base64Строка() и Base64Значение().РаботаСФайлами. Это гарантирует корректное распределение файлов по сетевым томам и корректное заполнение системных метаданных.