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

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

При программной отправке электронных писем из 1С разработчики часто формируют печатные формы, отчеты или выгрузки во временные файлы, прикрепляют их к письму и сразу после вызова отправки пытаются удалить с диска с помощью метода УдалитьФайлы(). Однако платформа нередко выдает ошибку о том, что файл занят другим процессом или приложением.

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

Причина блокировки файла в платформе 1С

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

Даже после успешного выполнения методов МПочта.Послать() и МПочта.Отключиться() объект Сообщение остается активным в памяти процедуры. Попытка вызвать УдалитьФайлы(ПолноеИмяФайла) в той же процедуре приводит к конфликту блокировки операционной системы, так как 1С сама продолжает держать файл открытым.

Рассмотрим основные способы гарантированного решения этой проблемы.

Способ 1. Очистка коллекции вложений письма

Самый простой и быстрый способ освободить удерживаемый дескриптор — принудительно очистить коллекцию вложений у объекта сообщения перед вызовом процедуры удаления файла. Посмотрим на пример кода:


// Отправка подготовленного письма
МПочта.Послать(Сообщение, ОбработкаТекстаИнтернетПочтовогоСообщения.НеОбрабатывать, ПротоколИнтернетПочты.SMTP);
МПочта.Отключиться();

// Очищаем вложения, освобождая файловый дескриптор
Сообщение.Вложения.Очистить();

// Теперь файл свободен и может быть удален
УдалитьФайлы(ПолноеИмяФайла);

Метод Очистить() уничтожает внутренние объекты вложений, закрывает потоки чтения, после чего метод УдалитьФайлы() отрабатывает без ошибок.

Способ 2. Обнуление переменной почтового сообщения

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


МПочта.Послать(Сообщение, ОбработкаТекстаИнтернетПочтовогоСообщения.НеОбрабатывать, ПротоколИнтернетПочты.SMTP);
МПочта.Отключиться();

// Сбрасываем объект сообщения
Сообщение = Неопределено;

// Удаляем временный файл
УдалитьФайлы(ПолноеИмяФайла);

Сборщик мусора платформы 1С при обнулении переменной освобождает связанные с объектом системные дескрипторы.

Способ 3. Вынос отправки письма в отдельную процедуру

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


Процедура СформироватьИОтправить()
    
    ПолноеИмяФайла = ПолучитьИмяВременногоФайла("html");
    Результат.Записать(ПолноеИмяФайла, ТипФайлаТабличногоДокумента.HTML5);
    
    ОтправитьПисьмоСФайлом(ПолноеИмяФайла, "Отчет.html");
    
    // В этой точке локальный контекст отправки уже уничтожен
    УдалитьФайлы(ПолноеИмяФайла);
    
КонецПроцедуры

Процедура ОтправитьПисьмоСФайлом(ПутьКФайлу, ИмяВложения)
    
    Сообщение = Новый ИнтернетПочтовоеСообщение;
    Сообщение.Получатели.Добавить("user@domain.com");
    Сообщение.Тема = "Тема письма";
    Сообщение.Вложения.Добавить(ПутьКФайлу, ИмяВложения);
    
    МПочта = Новый ИнтернетПочта;
    МПочта.Подключиться(Профиль);
    МПочта.Послать(Сообщение);
    МПочта.Отключиться();
    
КонецПроцедуры

Способ 4. Использование объекта ДвоичныеДанные

Метод Сообщение.Вложения.Добавить() поддерживает передачу не только строкового пути к файлу, но и объекта ДвоичныеДанные. При чтении файла в двоичные данные 1С сразу закрывает файл после считывания байтов в оперативную память.


// Считываем файл в двоичные данные
ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПолноеИмяФайла);

// Удалить временный файл с диска можно сразу же после считывания
УдалитьФайлы(ПолноеИмяФайла);

// Добавляем двоичные данные напрямую во вложение
Сообщение.Вложения.Добавить(ДвоичныеДанныеФайла, ИмяФайла);

МПочта.Послать(Сообщение);
МПочта.Отключиться();

Способ 5. Формирование вложений в оперативной памяти (ПотокВПамяти)

Наиболее эффективный и современный подход — полностью отказаться от промежуточной записи на жесткий диск. Если данные формируются программно (например, табличный документ Результат), их можно записать напрямую в ПотокВПамяти.

Посмотрим на пример:


Поток = Новый ПотокВПамяти;
Результат.Записать(Поток, ТипФайлаТабличногоДокумента.HTML5);
ДвоичныеДанныеВложения = Поток.ЗакрытьИПолучитьДвоичныеДанные();

Сообщение = Новый ИнтернетПочтовоеСообщение;
Сообщение.Получатели.Добавить("123@gmail.com");
Сообщение.Тема = ИмяФайла;
Сообщение.Вложения.Добавить(ДвоичныеДанныеВложения, ИмяФайла);

МПочта.Послать(Сообщение);
МПочта.Отключиться();

Этот метод полностью устраняет операции дискового ввода-вывода, исключает ошибки доступа к файловой системе и снимает необходимость контролировать удаление временных файлов.

Рекомендации по управлению временными файлами

При работе с временными файлами в 1С следует соблюдать несколько важных правил:

  1. Для генерации пути всегда используйте функцию ПолучитьИмяВременногоФайла(), а не ручное сложение пути через КаталогВременныхФайлов(), чтобы избежать коллизий имен файлов при параллельной работе пользователей.
  2. Обязательно удаляйте временные файлы самостоятельно. Хотя платформа очищает временные файлы при завершении сеанса, на сервере 1С (в фоновых и регламентных заданиях) сеансы могут существовать долго, что при интенсивном формировании отчетов быстро приводит к переполнению диска.
  3. По возможности отдавайте предпочтение объектам ДвоичныеДанные и ПотокВПамяти для работы без создания физических файлов на накопителе.
← На главную