Почему код загрузки файлов в 1С выполняется только в режиме отладчика и как это исправить?

Программист 1С v8.3 (Управляемые формы) 1С:Комплексная автоматизация IT и автоматизация бизнеса
← На главную

Разработчики 1С иногда сталкиваются с нетипичным поведением платформы: при пошаговом прохождении кода отладчиком (по клавишам F10/F11) файлы успешно загружаются и прикрепляются к документам, но стоит запустить систему в обычном режиме без отладки — и операция перестает выполняться без видимых ошибок.

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

Выясним причины нестабильной работы кода

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

  1. Некорректный идентификатор формы для временного хранилища. Если передать в функцию помещения файла уникальный идентификатор ссылки документа (Акт.УникальныйИдентификатор()) вместо уникального идентификатора открытой формы (ЭтаФорма.УникальныйИдентификатор), платформа 1С считает временное хранилище "осиротевшим". В обычном режиме сборщик мусора очищает его мгновенно перед вызовом сервера. При пошаговой отладке задержка выполнения удерживает ссылку в стеке, и файл успевает передаться на сервер.
  2. Использование устаревших синхронных методов. Метод ПоместитьФайлы() является синхронным. В современных конфигурациях на базе управляемых форм и тонкого клиента синхронные вызовы файловой системы работают нестабильно и зависят от режима сеанса.
  3. Влияние кэша и настроек расширения конфигурации. Если доработка вынесена в расширение, включенный Безопасный режим расширения или устаревший серверный кэш метаданных могут блокировать вызовы файловых операций.

Проанализируем исходный код с ошибкой

Рассмотрим фрагмент кода, в котором проявляется данная проблема при попытке прикрепить файл PDF к документу:


&НаКлиенте
Функция ДобавитьПДФ(Акт, ПДФ)
    
    Файл = Новый Файл(ПДФ);
    ВладелецФайла = Акт;
    ИмяСоздаваемогоФайла = Файл.ИмяБезРасширения;        
    ПолноеИмяФайла = ПДФ;
    
    // ОШИБКА: Берется UUID ссылки документа, а не управляемой формы
    ИдентификаторФормы = Акт.УникальныйИдентификатор();
    
    ОбщиеНастройки = ФайловыеФункцииСлужебныйКлиентСервер.ОбщиеНастройкиРаботыСФайлами();
    ФайловыеФункцииСлужебныйКлиентСервер.ПроверитьВозможностьЗагрузкиФайла(Файл);
    
    ВремяИзмененияУниверсальное = Файл.ПолучитьУниверсальноеВремяИзменения();
    
    ПомещаемыеФайлы = Новый Массив;
    Описание = Новый ОписаниеПередаваемогоФайла(Файл.ПолноеИмя, "");
    ПомещаемыеФайлы.Добавить(Описание);
    
    ПомещенныеФайлы = Новый Массив;
    
    // Передача некорректного ИдентификаторФормы приводит к очистке хранилища
    Если НЕ ПоместитьФайлы(ПомещаемыеФайлы, ПомещенныеФайлы, , Ложь, ИдентификаторФормы) Тогда
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Ошибка при помещении файла во временное хранилище.");
    КонецЕсли;
    
    АдресВременногоХранилищаФайла = ПомещенныеФайлы[0].Хранение;
    
    // Вызов сервера для создания записи о файле
    ПрисоединенныеФайлыСлужебныйВызовСервера.ДобавитьФайл(
        ВладелецФайла,
        ИмяСоздаваемогоФайла,
        ОбщегоНазначенияКлиентСервер.РасширениеБезТочки(Файл.Расширение),
        ,
        ВремяИзмененияУниверсальное,
        АдресВременногоХранилищаФайла);  
        
КонецФункции

Способ 1. Исправление работы с УникальнымИдентификатором

Разберем по шагам, как исправить логику привязки временного хранилища. Чтобы временное хранилище существовало до конца выполнения серверной процедуры, его нужно привязать к действующей форме или передать уникальный идентификатор без привязки к конкретной форме.

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


// В контексте формы передаем УникальныйИдентификатор самой формы:
ИдентификаторФормы = ЭтаФорма.УникальныйИдентификатор;

Если код выполняется в общем модуле на клиенте вне контекста формы, создадим новый УникальныйИдентификатор или не будем ограничивать время жизни хранилища формой:


// Создаем независимый идентификатор для временного хранилища
ИдентификаторХранилища = Новый УникальныйИдентификатор;
АдресХранилища = ПоместитьВоВременноеХранилище(ДвоичныеДанныеФайла, ИдентификаторХранилища);

Способ 2. Переход на работу через ДвоичныеДанные (Рекомендуемый)

Саймый надежный способ загрузки файлов без зависимости от отладчика и интерактивных форм — чтение файла в объект ДвоичныеДанные непосредственно перед отправкой на сервер.

Рассмотрим пример правильного кода чтения и передачи файла:


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

Способ 3. Проверка настроек расширения и очистка кэша

Если код вынесен в расширение конфигурации, проверим дополнительные параметры платформы:

  1. Безопасный режим расширения: В конфигураторе открываем свойства расширения и снимаем флажок Безопасный режим. В безопасном режиме платформой могут блокироваться файловые операции на клиенте.
  2. Защита от опасных действий: При работе с файловой системой проверяем настройки пользователя и при необходимости отключаем предупреждения защиты от опасных действий.
  3. Очистка кэша: Очищаем локальный кэш тонкого клиента (удалением базы из списка или очисткой папок %LOCALAPPDATA%\1C\1cv8 и %APPDATA%\1C\1cv8). При наличии доступа к серверу перезапускаем службу 1C:Предприятие для обновления серверного кэша метаданных.
← На главную