В процессе автоматизации обмена данными или обработки выгрузок часто возникает задача синхронизации двух каталогов. Например, нам нужно очистить "Папку А" от всех файлов, которые уже присутствуют в "Папке Б", ориентируясь исключительно на их имена. Разберем, как это реализовать правильно, избегая типичных ошибок новичков, связанных с объектной моделью 1С.
Первая ошибка, с которой сталкиваются разработчики — попытка сравнить сами объекты типа Файл или их полные пути. Рассмотрим ситуацию: у нас есть файл "report.dbf" в первой папке и такой же во второй. Их полные пути (свойство ПолноеИмя) будут разными, так как они включают путь к каталогу. Поэтому для корректного сопоставления мы должны использовать свойство Имя или ИмяБезРасширения.
Проанализируем простейший алгоритм "в лоб" (использование вложенных циклов):
// Определяем пути к каталогам
Каталог1 = "C:\Data\Folder1";
Каталог2 = "C:\Data\Folder2";
Маска = "*.dbf";
// Получаем массивы файлов из обеих папок
ФайлыПапки1 = НайтиФайлы(Каталог1, Маска, Ложь);
ФайлыПапки2 = НайтиФайлы(Каталог2, Маска, Ложь);
// Перебираем файлы первой папки
Для Каждого Файл1 Из ФайлыПапки1 Цикл
// Для каждого файла ищем совпадение во второй папке
Для Каждого Файл2 Из ФайлыПапки2 Цикл
Если Файл1.Имя = Файл2.Имя Тогда
// Если имена совпали, удаляем файл из ПЕРВОЙ папки
Попытка
УдалитьФайлы(Файл1.ПолноеИмя);
Сообщить("Удален файл: " + Файл1.Имя);
Исключение
Сообщить("Не удалось удалить файл: " + Файл1.ПолноеИмя + ". Возможно, он занят.");
КонецПопытки;
Прервать; // Выходим из внутреннего цикла, так как файл уже удален
КонецЕсли;
КонецЦикла;
КонецЦикла;
Рассмотрим ситуацию, когда файлов в папках очень много (сотни или тысячи). Вложенный цикл в этом случае будет работать крайне медленно, так как количество операций сравнения растет в геометрической прогрессии. Чтобы ускорить процесс, проанализируем возможность использования объекта Соответствие.
Выясним, как это работает: мы один раз обходим вторую папку и записываем все имена файлов в "ключи" соответствия. Поиск по ключу в 1С происходит практически мгновенно.
ИменаФайловВоВторойПапке = Новый Соответствие;
ФайлыПапки2 = НайтиФайлы(Каталог2, "*.dbf", Ложь);
Для Каждого Файл2 Из ФайлыПапки2 Цикл
ИменаФайловВоВторойПапке.Вставить(ВРег(Файл2.Имя), Истина);
КонецЦикла;
ФайлыПапки1 = НайтиФайлы(Каталог1, "*.dbf", Ложь);
Для Каждого Файл1 Из ФайлыПапки1 Цикл
// Проверяем наличие имени в соответствии (регистронезависимо)
Если ИменаФайловВоВторойПапке.Получить(ВРег(Файл1.Имя)) <> Неопределено Тогда
УдалитьФайлы(Файл1.ПолноеИмя);
КонецЕсли;
КонецЦикла;
Иногда задача усложняется: нужно искать файлы не только в корне, но и во всех подпапках, но при этом игнорировать определенные каталоги (например, саму "Папку2" или служебные архивы). Метод НайтиФайлы с параметром Истина (рекурсия) выдаст нам плоский список всех файлов во всех вложенных директориях.
Посмотрим на пример фильтрации путей:
МаскаФайла = "*.dbf";
// Ищем во всех подпапках
НайденныеФайлы = НайтиФайлы(ОбщийКаталог, МаскаФайла, Истина);
Для Каждого ТекущийФайл Из НайденныеФайлы Цикл
// Проверяем, не является ли найденный объект каталогом
Если ТекущийФайл.ЭтоКаталог() Тогда
Продолжить;
КонецЕсли;
// Исключаем обработку файлов, находящихся в конкретных папках
// Используем функцию СтрНайти для анализа полного пути
Если СтрНайти(ТекущийФайл.ПолноеИмя, "\Архив\") > 0
ИЛИ СтрНайти(ТекущийФайл.ПолноеИмя, "\Temp\") > 0 Тогда
Продолжить;
КонецЕсли;
// Далее логика обработки файла...
КонецЦикла;
При работе с DBF-файлами через объект XBase часто возникает проблема: файл не удаляется, так как он "занят". Выясним причину: 1С удерживает дескриптор файла до тех пор, пока не будет вызван метод ЗакрытьФайл() или пока объект не будет уничтожен сборщиком мусора.
Разберем правильный цикл работы с временным DBF-файлом:
КаталогВременныхФайлов().Новый XBase.ФайлДБФ.ЗакрытьФайл().ФайлДБФ = Неопределено.УдалитьФайлы().Пример массовой очистки временного каталога от остаточных файлов:
// Будьте осторожны с этой командой, используйте маску!
ПутьВременных = КаталогВременныхФайлов();
Попытка
УдалитьФайлы(ПутьВременных, "*.dbf");
Сообщить("Временные DBF-файлы успешно удалены.");
Исключение
Сообщить("Некоторые файлы не удалось удалить, так как они используются программой.");
КонецПопытки;
Проанализируем несколько технических моментов, которые помогут избежать потери данных:
"File.dbf" = "file.dbf" может вернуть Ложь в зависимости от настроек. Рекомендуем всегда использовать функцию ВРег() или НРег() при сравнении имен.УдалитьФайлы() на этапе отладки лучше использовать ПереместитьФайл() в специальную корзину. Это позволит восстановить данные, если логика сравнения имен сработала не так, как ожидалось.1C:Enterprise Server, есть права на чтение и удаление в указанных сетевых папках.Файл.Размер()) или дате последней модификации.Таким образом, мы разобрали, что для корректного сравнения необходимо использовать свойство Имя, для быстродействия применять Соответствие, а для стабильной работы с DBF — тщательно контролировать закрытие объектов XBase перед попыткой удаления файлов.