Как решить проблему с ошибкой доступа «Access is denied» при удалении файлов в 1С?

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

При программной работе с файлами на сервере 1С (особенно при обработке изображений, генерации PDF-документов или вызове внешних консольных утилит вроде ImageMagick) разработчики часто сталкиваются с неприятной ошибкой: «Ошибка при вызове метода контекста (УдалитьФайлы)... Ошибка доступа к файлу. 5(0x00000005): Access is denied». При этом вручную под своей учетной записью администратор может легко удалить этот файл.

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

Причина 1: Специфика контекста выполнения и права службы сервера 1С

Если ваша база данных работает в клиент-серверном режиме (на базе MS SQL Server, PostgreSQL и т.д.), любой код, написанный без явной директивы &НаКлиенте, выполняется на стороне сервера приложений 1С. Это означает следующее:

  1. Путь к файлу (например, C:\Файлы1с\20191224\GARD05_1.jpg) обрабатывается локально на сервере, а не на вашем рабочем компьютере.
  2. Все операции чтения, записи и удаления выполняются от имени операционной системы Windows, под которой запущена служба сервера 1С (обычно это технический пользователь USR1CV8 или аналогичный системный аккаунт).

Даже если вы лично зашли в Windows под учетной записью Администратора и можете вручную удалять любые файлы в папке C:\Файлы1с\, у пользователя USR1CV8 может попросту не быть прав на удаление в этой директории. Ему необходимы полные права (Full Control) на уровне безопасности NTFS.

Причина 2: Парадокс перемещения файла и особенности файловой системы NTFS

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

Это связано с логикой работы файловой системы NTFS под управлением ОС Windows:

Причина 3: Установленный атрибут «Только чтение» (Read-Only)

Метод платформы 1С УдалитьФайлы() имеет жесткое ограничение: он всегда завершается ошибкой доступа (Error 5), если у удаляемого файла установлен системный атрибут «Только чтение». Внешние конвертеры или процессы копирования файлов часто автоматически присваивают этот атрибут результирующим файлам.

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


ФайлНаДиске = Новый Файл(СтароеИмя);
Если ФайлНаДиске.Существует() Тогда
    // Снимаем защиту от записи и удаления
    ФайлНаДиске.УстановитьТолькоЧтение(Ложь); 
    
    Попытка
        УдалитьФайлы(СтароеИмя);
    Исключение
        ЗаписьЖурналаРегистрации("УдалениеФайлов", УровеньЖурналаРегистрации.Предупреждение, , , 
            "Не удалось удалить файл: " + СтароеИмя + ". Описание: " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
    КонецПопытки;
КонецЕсли;

Причина 4: Скрытая блокировка дескриптора самой платформой 1С

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

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

Чтобы избежать этой проблемы, перед вызовом удаления необходимо явно очищать переменные, ссылающиеся на файл, присваивая им значение Неопределено:


МояКартинка = Неопределено;
МоиДвоичныеДанные = Неопределено;

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

Причина 5: Эффект «гонки» процессов (Антивирусы и индексаторы)

Даже если в коде запуска внешнего приложения (например, утилиты ImageMagick) установлен параметр ожидания завершения (значение Истина в методе ЗапуститьПриложение), сразу после закрытия утилиты файл может стать временно недоступным:

  1. Антивирусное ПО (например, Windows Defender) мгновенно перехватывает свежесозданный или измененный сторонним процессом файл для сканирования на угрозы, на доли секунды блокируя к нему доступ.
  2. Служба индексирования Windows (Search Indexer) может захватить файл для обновления поискового индекса каталога.

Если 1С пытается выполнить метод УдалитьФайлы() ровно в ту же миллисекунду, когда антивирус проверяет файл, операционная система вернет ошибку доступа (Error 5 или Error 32).

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


УспешноУдалено = Ложь;

Для Итератор = 1 По 5 Цикл // Выполняем до 5 попыток удаления
    Попытка
        УдалитьФайлы(СтароеИмя);
        УспешноУдалено = Истина;
        Прервать; // Удаление прошло успешно, выходим из цикла
    Исключение
        // Файл временно заблокирован внешним процессом.
        // Выдерживаем паузу в 1 секунду перед следующей попыткой.
        // Для серверного кода можно использовать метод ожидания:
        ПриостановитьВыполнение(1); 
    КонецПопытки;
КонецЦикла;

Если Не УспешноУдалено Тогда
    ВызватьИсключение "Не удалось удалить файл после нескольких попыток: " + СтароеИмя;
КонецЕсли;

Комплексный алгоритм безопасного удаления файлов

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


Процедура БезопасноУдалитьФайл(Знач ПолныйПутьКФайлу) Экспорт
    
    ФайлНаДиске = Новый Файл(ПолныйПутьКФайлу);
    Если Не ФайлНаДиске.Существует() Тогда
        Возврат;
    КонецЕсли;
    
    // Шаг 1: Принудительно снимаем атрибут "Только чтение"
    Если ФайлНаДиске.ПолучитьТолькоЧтение() Тогда
        Попытка
            ФайлНаДиске.УстановитьТолькоЧтение(Ложь);
        Исключение
            // Запишем предупреждение, если не удалось изменить атрибуты
            ЗаписьЖурналаРегистрации("УдалениеФайлов.Атрибуты", 
                УровеньЖурналаРегистрации.Предупреждение, , , 
                "Не удалось снять атрибут Только Чтение с файла: " + ПолныйПутьКФайлу);
        КонецПопытки;
    КонецЕсли;
    
    // Шаг 2: Удаление файла с защитой от блокировок ОС (цикл с паузой)
    УспешноУдалено = Ложь;
    МаксимальноеКоличествоПопыток = 5;
    
    Для ПопыткаУдаления = 1 По МаксимальноеКоличествоПопыток Цикл
        Попытка
            УдалитьФайлы(ПолныйПутьКФайлу);
            УспешноУдалено = Истина;
            Прервать;
        Исключение
            Если ПопыткаУдаления < МаксимальноеКоличествоПопыток Тогда
                // Ждем освобождения дескриптора операционной системой
                ПриостановитьВыполнение(1); 
            КонецЕсли;
        КонецПопытки;
    КонецЦикла;
    
    // Шаг 3: Если файл так и не удалился, применяем резервный метод "Перемещение во временный каталог"
    Если Не УспешноУдалено Тогда
        Попытка
            КаталогВременныхФайлов = КаталогВременныхФайлов();
            ИмяВременногоФайла = КаталогВременныхФайлов + ПолучитьИмяВременногоФайла(ФайлНаДиске.Расширение);
            ПереместитьФайл(ПолныйПутьКФайлу, ИмяВременногоФайла);
            
            // Пробуем удалить уже перемещенный временный файл
            УдалитьФайлы(ИмяВременногоФайла);
        Исключение
            // Если и это не помогло, фиксируем критическую ошибку прав NTFS на сервере
            ВызватьИсключение "Критическая ошибка доступа при удалении файла: " + ПолныйПутьКФайлу 
                + Символы.ПС + КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
        КонецПопытки;
    КонецЕсли;
    
КонецПроцедуры

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

← На главную