Как сравнить одну коллекцию файлов с другой в C #? - PullRequest
0 голосов
/ 06 декабря 2009

Я только изучаю C # (возился с ним около 2 дней) и решил, что для простоты я перестрою старое приложение, которое я сделал в VB6 для синхронизации файлов (обычно по сети) .

Когда я писал код на VB 6, он работал примерно так:

  1. Создать Scripting.FileSystemObject
  2. Создание объектов каталога для источника и назначения
  3. Создание файла со списком объектов для источника и назначения
  4. Переберите исходный объект и проверьте, существует ли он в месте назначения
    • если нет, создайте его
    • если это так, проверьте, является ли исходная версия более новой или большей, и, если это так, перезапишите другую

Пока что вот что у меня есть:

private bool syncFiles(string sourcePath, string destPath) {
    DirectoryInfo source = new DirectoryInfo(sourcePath);
    DirectoryInfo dest = new DirectoryInfo(destPath);

    if (!source.Exists) {
        LogLine("Source Folder Not Found!");
        return false;
    }

    if (!dest.Exists) {
        LogLine("Destination Folder Not Found!");
        return false;
    }

    FileInfo[] sourceFiles = source.GetFiles();
    FileInfo[] destFiles = dest.GetFiles();

    foreach (FileInfo file in sourceFiles) {
        // check exists on file
    }

    if (optRecursive.Checked) {
        foreach (DirectoryInfo subDir in source.GetDirectories()) {
            // create-if-not-exists destination subdirectory
            syncFiles(sourcePath + subDir.Name, destPath + subDir.Name);
        }
    }
    return true;
}

Я читал примеры, которые, по-видимому, рекомендуют использовать объекты FileInfo или DirectoryInfo для выполнения проверок с помощью свойства «Exists», но я специально ищу способ поиска в существующей коллекции / списке файлов, а не живых проверок для файловая система для каждого файла, так как я буду делать это по сети и постоянно возвращаться к каталогу с несколькими тысячами файлов медленно-медленно-медленно.

Заранее спасибо.

Ответы [ 2 ]

5 голосов
/ 06 декабря 2009

Метод GetFiles() получит только те файлы, которые существуют. Это не составляет случайные файлы, которые не существуют. Поэтому все, что вам нужно сделать, это проверить, существует ли он в другом списке.

Что-то в строках может сработать:

var sourceFiles = source.GetFiles();
var destFiles = dest.GetFiles();

foreach (var file in sourceFiles)
{
    if(!destFiles.Any(x => x.Name == file.Name))
    {
        // Do whatever
    }
}

Примечание: Вы, конечно, не можете гарантировать, что что-то не изменилось после того, как вы сделали вызовы на GetFiles(). Например, файл мог быть удален или переименован, если вы попытаетесь скопировать его позже.


Возможно, можно как-то сделать лучше, используя метод Except или что-то подобное. Например что-то вроде этого:

var sourceFiles = source.GetFiles();
var destFiles = dest.GetFiles();

var sourceFilesMissingInDestination = sourceFiles.Except(destFiles, new FileNameComparer());

foreach (var file in sourceFilesMissingInDestination)
{
    // Do whatever
}

Где FileNameComparer реализован так:

public class FileNameComparer : IEqualityComparer<FileInfo>
{
    public bool Equals(FileInfo x, FileInfo y)
    {
        return Equals(x.Name, y.Name);
    }


    public int GetHashCode(FileInfo obj)
    {
        return obj.Name.GetHashCode();
    }
}     

Не проверено, хотя: p

4 голосов
/ 06 декабря 2009

Одна маленькая деталь вместо

 sourcePath + subDir.Name

Я бы использовал

 System.IO.Path.Combine(sourcePath, subDir.Name)

Path выполняет надежные, независимые от ОС операции над файлами и папками.

Также я замечаю, что optRecursive.Checked выскочил из ниоткуда. В качестве хорошего дизайна укажите параметр:

bool syncFiles(string sourcePath, string destPath, bool checkRecursive)

И поскольку вы упоминаете, что он может использоваться для большого количества файлов, обратите внимание на .NET 4, он имеет IEnumerable замену GetFiles (), которая позволит вам обрабатывать это потоковым способом.

...