В процессе разработки в среде 1С программисты часто сталкиваются с необходимостью конвертации документов или извлечения текста из файлов MS Word. Типичный сценарий: создание временного файла, выполнение операций через COM-объект и последующее удаление этого файла. Однако на практике метод УдалитьФайлы часто «молчит» или выдает ошибку доступа, причем проблема может проявляться только в реальном режиме работы, успешно «проскакивая» во время отладки. Давайте подробно разберем, почему это происходит и как построить надежный механизм очистки временных данных.
Проанализируем ситуацию, описанную разработчиком. При установке точки останова в конфигураторе 1С выполнение кода приостанавливается. В это время операционная система и внешнее приложение (Word) успевают завершить все фоновые операции. Когда программист нажимает «Продолжить», файл уже свободен, и 1С легко его удаляет. В обычном же режиме (рантайме) интерпретатор 1С выполняет команды со скоростью в тысячи раз превышающей скорость закрытия тяжелых приложений, таких как winword.exe.
Команда ФайлВ.Quit() — это лишь сигнал приложению Word начать процедуру закрытия. Word может продолжать удерживать файловый дескриптор еще несколько сотен миллисекунд (или даже секунд), сохраняя настройки в Normal.dotm или очищая кэш. В этот момент 1С уже вызывает УдалитьФайлы, получает отказ от операционной системы и идет дальше. Выясним, как гарантированно избежать этой коллизии.
Самое важное правило при работе с COM-соединениями: 1С должна «отпустить» объект не только логически, но и физически. Даже после вызова метода Quit() переменная в 1С продолжает хранить ссылку на объект. Пока эта ссылка жива, COM-сервер может оставаться в памяти в «подвешенном» состоянии.
Рассмотрим правильную последовательность действий:
// Инициализация
ВремФайл = ПолучитьИмяВременногоФайла(".html");
WordApp = Новый COMОбъект("Word.Application");
// ... выполнение каких-либо действий с документом ...
// Завершение работы
WordApp.Quit();
// КРИТИЧЕСКИ ВАЖНО: Обнуляем переменную
WordApp = Неопределено;
// Попытка удаления
Попытка
УдалитьФайлы(ВремФайл);
Исключение
ЗаписьЖурналаРегистрации("ОчисткаФайлов", УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки());
КонецПопытки;
Присваивание Неопределено принудительно уменьшает счетчик ссылок на объект. Для 1С это сигнал, что объект больше не нужен, и сборщик мусора (Garbage Collector) может корректно завершить связь с внешней библиотекой.
Если присваивание Неопределено не помогает (например, из-за вмешательства антивируса, который решил проверить файл сразу после его сохранения Word-ом), нам стоит применить тактику повторных попыток. Разберем, как реализовать небольшую паузу без блокировки всего интерфейса или сервера.
Проанализируем пример кода с циклом ожидания:
УспешноУдалено = Ложь;
Для Счетчик = 1 По 10 Цикл // Делаем 10 попыток
Попытка
УдалитьФайлы(ВремФайл);
УспешноУдалено = Истина;
Прервать;
Исключение
// Если файл занят, ждем немного
#Если Клиент Тогда
// В клиентском приложении можно использовать небольшую паузу
// ВНИМАНИЕ: Не рекомендуется для серверного кода
#КонецЕсли
КонецПопытки;
КонецЦикла;
В серверном коде для реализации задержки лучше использовать метод Ждать (если версия платформы позволяет) или просто повторять попытку через увеличивающиеся интервалы времени в фоновом задании.
Начиная с версии платформы 8.3.15, в 1С появился замечательный объект — МенеджерВременныхФайлов. Это профессиональное решение проблемы «мусора» в папке Temp. Вместо того чтобы вручную следить за каждым файлом, мы можем «доверить» их менеджеру.
Посмотрим на пример работы с этим объектом:
МенеджерВТ = Новый МенеджерВременныхФайлов;
// Файл привязывается к менеджеру
ИмяФайла = МенеджерВТ.СформироватьИмяВременногоФайла(".docx");
// Работаем с Word...
// ...
// Нам не нужно вызывать УдалитьФайлы!
// Как только объект "МенеджерВТ" выйдет из области видимости (завершится процедура)
// или мы вызовем МенеджерВТ.Очистить(), платформа сама удалит все файлы.
// Если файл занят в данный момент, платформа повторит попытку позже автоматически.
Важное преимущество: Менеджер временных файлов гарантирует очистку даже при аварийном завершении работы скрипта, что делает систему гораздо более отказоустойчивой.
Стоит обратить внимание на важную деталь: функция ПолучитьИмяВременногоФайла() не просто возвращает строку с путем, она физически создает пустой файл нулевого размера на диске. Когда Word пытается выполнить SaveAs, он обнаруживает, что файл уже существует. В некоторых конфигурациях прав доступа это может вызвать конфликт: Word перезаписывает файл, но оставляет за собой эксклюзивные права на владение им.
Попробуйте альтернативный подход:
КаталогВременныхФайлов().Новый УникальныйИдентификатор()).В этом случае Word будет «первичным» создателем файла, и проблем с правами при закрытии будет меньше.
Если ваш код выполняется на стороне сервера 1С, проанализируем ситуацию с правами доступа. Служба 1С обычно работает под учетной записью USR1CV8. Убедитесь, что:
Temp (обычно это C:\Windows\Temp или профиль пользователя службы).Мы выяснили, что основная причина невозможности удаления файла — асинхронность работы Windows и удерживание ссылок внутри 1С. Для исправления ситуации всегда обнуляйте COM-переменные (Неопределено), используйте современные механизмы платформы, такие как МенеджерВременныхФайлов, и не забывайте про обработку исключений. Помните, что надеяться на «автоматическую очистку при перезагрузке сервера» — плохая практика, которая со временем приведет к нехватке свободного места на диске.