Как сравнить DBF-файлы в разных папках по имени и удалить дубликаты в 1С

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

В процессе автоматизации обмена данными или обработки выгрузок часто возникает задача синхронизации двух каталогов. Например, нам нужно очистить "Папку А" от всех файлов, которые уже присутствуют в "Папке Б", ориентируясь исключительно на их имена. Разберем, как это реализовать правильно, избегая типичных ошибок новичков, связанных с объектной моделью 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 Тогда
        Продолжить;
    КонецЕсли;

    // Далее логика обработки файла...
КонецЦикла;

Работа с XBase и очистка временных файлов

При работе с DBF-файлами через объект XBase часто возникает проблема: файл не удаляется, так как он "занят". Выясним причину: 1С удерживает дескриптор файла до тех пор, пока не будет вызван метод ЗакрытьФайл() или пока объект не будет уничтожен сборщиком мусора.

Разберем правильный цикл работы с временным DBF-файлом:

  1. Создаем или копируем файл в КаталогВременныхФайлов().
  2. Открываем его через Новый XBase.
  3. Выполняем необходимые операции (чтение, запись).
  4. ОБЯЗАТЕЛЬНО вызываем ФайлДБФ.ЗакрытьФайл().
  5. Для гарантии очистки памяти присваиваем ФайлДБФ = Неопределено.
  6. Только после этого вызываем УдалитьФайлы().

Пример массовой очистки временного каталога от остаточных файлов:


// Будьте осторожны с этой командой, используйте маску!
ПутьВременных = КаталогВременныхФайлов();
Попытка
    УдалитьФайлы(ПутьВременных, "*.dbf");
    Сообщить("Временные DBF-файлы успешно удалены.");
Исключение
    Сообщить("Некоторые файлы не удалось удалить, так как они используются программой.");
КонецПопытки;

Важные рекомендации и нюансы

Проанализируем несколько технических моментов, которые помогут избежать потери данных:

Таким образом, мы разобрали, что для корректного сравнения необходимо использовать свойство Имя, для быстродействия применять Соответствие, а для стабильной работы с DBF — тщательно контролировать закрытие объектов XBase перед попыткой удаления файлов.

← На главную