При разработке различных интеграций и выгрузок (например, ежедневный экспорт данных для WMS-систем) мы часто сталкиваемся с необходимостью перезаписывать один и тот же файл CSV. Однако на практике можно столкнуться со странной ситуацией: файл успешно создается и сохраняется, но при попытке его перезаписать система выдает ошибку, а сам файл невозможно удалить даже в проводнике Windows. Рассмотрим подробнее, почему возникает такая проблема и как правильно ее решить.
Часто разработчики пишут примерно следующий код для выгрузки данных в файл:
Date_time_stamp = XMLСтрока(ТекущаяДата());
Каталог = Справочники._КЕ_СправочникКонстант.НайтиПоКоду("WMSEXPORT").Значение;
Текст = Новый ТекстовыйДокумент;
CSVНаСервере(Текст, Date_time_stamp);
Попытка
Текст.Записать(Каталог, КодировкаТекста.UTF16);
Исключение
Попытка
Каталог = Каталог + "_file_locked.csv";
Текст.Записать(Каталог, КодировкаТекста.UTF16);
Исключение
КонецПопытки;
КонецПопытки;
В этом примере мы видим использование объекта ТекстовыйДокумент. Автор кода жалуется, что при повторном запуске файл оказывается чем-то занят, перезаписать его нельзя, а попытки закрыть процесс Excel или выгнать пользователей из базы не приносят результата. Выясним причину такого поведения.
&НаСервере или в фоновом задании), создание и запись файлов происходят от имени учетной записи операционной системы, под которой запущена служба Агента сервера 1С (обычно это USR1CV8). Часто этот пользователь имеет права только на создание файла. Если затем вы пытаетесь открыть этот файл под своим пользователем Windows или сервер 1С пытается его перезаписать без достаточных прав на модификацию, ОС блокирует действие. В нашем случае именно отсутствие прав на изменение стало корнем проблемы.Чтобы избежать "фантомных" блокировок и долгих поисков ошибки, перепишем наш подход к выгрузке. Во-первых, проанализируем, как правильно обрабатывать исключения.
Шаг 1: Правильная обработка исключений
Вместо того чтобы подавлять ошибку в пустом блоке Исключение, всегда используйте функцию ОписаниеОшибки(). Это сразу покажет, что проблема звучит как "Отказано в доступе" (проблема с правами), а не "Файл занят другим процессом".
Попытка
Текст.Записать(Каталог, КодировкаТекста.UTF16);
Исключение
ТекстОшибки = ОписаниеОшибки();
ЗаписьЖурналаРегистрации("ВыгрузкаCSV", УровеньЖурналаРегистрации.Ошибка,,, ТекстОшибки);
Сообщить("Ошибка при записи файла: " + ТекстОшибки);
КонецПопытки;
Шаг 2: Использование объекта ЗаписьТекста
Для потоковой записи файлов логов и CSV лучше использовать объект ЗаписьТекста, а не ТекстовыйДокумент. Главное отличие в том, что у объекта ЗаписьТекста есть явный метод Закрыть(), который гарантированно освобождает дескриптор файла в ОС.
ИмяФайла = Каталог + "\" + Формат(ТекущаяДата(), "ДФ=yyyy-MM-dd") + ".csv";
Запись = Новый ЗаписьТекста(
ИмяФайла,
КодировкаТекста.ANSI,
Символы.ПС,
Ложь // Ложь - перезаписывать файл, Истина - дописывать в конец
);
Запись.ЗаписатьСтроку("Колонка1;Колонка2;Колонка3");
Запись.ЗаписатьСтроку("Значение1;Значение2;Значение3");
// Обязательно закрываем файл для снятия блокировки ОС
Запись.Закрыть();
Рассмотрим самый надежный подход при регулярных выгрузках (например, обмене с WMS). Писать файл напрямую в "боевую" целевую папку — плохая практика. Сторонняя система может начать чтение файла до того, как 1С закончит его запись. Кроме того, в целевой папке могут быть сложные настройки прав.
Посмотрим на пример правильного алгоритма: сначала пишем во временный каталог, затем перемещаем.
// 1. Получаем путь к временному файлу
ВременныйФайл = ПолучитьИмяВременногоФайла("csv");
// 2. Записываем данные во временный файл (здесь 100% есть права у сервера 1С)
Запись = Новый ЗаписьТекста(ВременныйФайл, КодировкаТекста.UTF8);
Запись.ЗаписатьСтроку("Данные;Для;Выгрузки");
Запись.Закрыть();
// 3. Формируем итоговый путь
ИтоговыйПуть = Каталог + "\export.csv";
// 4. Перемещаем файл. Операция на уровне ОС проходит мгновенно.
Попытка
ПереместитьФайл(ВременныйФайл, ИтоговыйПуть);
Исключение
Сообщить("Не удалось переместить файл. Причина: " + ОписаниеОшибки());
КонецПопытки;
Используя метод ПереместитьФайл(), мы решаем сразу две проблемы: исключаем чтение недописанного файла сторонними программами и минимизируем время, в течение которого 1С держит блокировку в целевом каталоге. Если вы столкнулись с невозможностью перезаписать файл, обязательно проверьте права пользователя USR1CV8 на изменение файлов в нужной директории и примените описанный выше подход с временными файлами.