Member 12969219 Ответов: 4

Как скопировать только новые или измененные файлы в C#


Я знаю, что это, вероятно, было сделано и обсуждено бесчисленное количество раз, но я не могу найти ответ, который я ищу.

Я пытаюсь создать простое консольное приложение “копия каталога/файла" на языке C#. Что мне нужно, так это скопировать все папки и файлы (сохраняя исходную иерархию) с одного диска на другой, например с диска C:\Data чтобы вести машину E:\Data.

Однако я хочу, чтобы он только копировал любые новые или измененные файлы из источника в пункт назначения.
Если файл на целевом диске новее, чем на исходном диске, то он не копируется.

(проблема)
В коде, который у меня есть, он сравнивает файл "abc.pdf" в исходном коде с файлом "xyz.pdf" в целевом коде и, таким образом, перезаписывает целевой файл с тем, что находится в исходном коде, даже если конечный файл является более новым. Я пытаюсь понять, как сделать так, чтобы он сравнивал "abc.pdf" в источнике с "abc.pdf" в пункте назначения.
Это работает, если я детализирую исходный и конечный файлы до определенного файла, но когда я возвращаюсь на уровень папки, он перезаписывает конечный файл исходным файлом, даже если конечный файл является более новым.

(мои решения – это не сработало)
Я подумал, поставив “если (файл.LastWriteTime > пункт назначения.LastWriteTime)” после команды “foreach”, что он будет сравнивать файлы в двух папках, File1 source и File1 destination, но это не так.

Похоже, я что-то упускаю в операторах “FileInfo []”, “foreach” или “if”, чтобы сделать это сравнение один к одному. Я думаю, может быть, какая-то ссылка на “путь".Комбинируйте” оператор "или “поисковый вариант".AllDirectories”, но я не уверен.

Есть предложения?
Как вы можете видеть из моего базового примера кода, я новичок в C#, поэтому, пожалуйста, сформулируйте свой ответ простыми словами.

Спасибо.
Ниже приведен код, который я пробовал, но он не работает.

Что я уже пробовал:

class Copy  
{  
    public static void CopyDirectory(DirectoryInfo source, DirectoryInfo destination)  
    {  
        if (!destination.Exists)  
        {  
            destination.Create();  
        }  
        // Copy files.  
        FileInfo[] files = source.GetFiles();  
        FileInfo[] destFiles = destination.GetFiles();  
        foreach (FileInfo file in files)  
            foreach (FileInfo fileD in destFiles)  
                // Copy only modified files    
                    if (file.LastWriteTime > fileD.LastWriteTime)  
                    {  
                        file.CopyTo(Path.Combine(destination.FullName,  
                        file.Name), true);  
                    }  

                // Copy all new files  
                else  
                if (!fileD.Exists)  
                {  
                    file.CopyTo(Path.Combine(destination.FullName, file.Name), true);  
                }  
        // Process subdirectories.  
        DirectoryInfo[] dirs = source.GetDirectories();  
        foreach (DirectoryInfo dir in dirs)  
        {  
            // Get destination directory.  
            string destinationDir = Path.Combine(destination.FullName, dir.Name);  
            // Call CopyDirectory() recursively.  
            CopyDirectory(dir, new DirectoryInfo(destinationDir));  
        }  
    }  
}  

4 Ответов

Рейтинг:
28

RickZeeland

После этой строки:

foreach (FileInfo fileD in destFiles) 
вы должны сначала сравнить имена файлов для равенства, и только потом делать копирование:
If (file.Name.equals(fileD.Name))
{
// your code ...
}
Если вам нужно что-то более продвинутое, вы можете попробовать решение Джерри, которое включает в себя использование LINQ.


Member 12969219

Хорошо, я думал, что, получая "FileInfo", я получаю имя файла и дату модификации, потому что я могу распечатать детали файла в "консоли.метод WriteLine".

Member 12969219

О боже. Это работает! Огромное спасибо. Это та команда, которую я искал, но не знал, что она существует. Отличный способ закончить неделю.

BillWoodruff

+5

Рейтинг:
2

Member 12969219

Обновление:

Я изменил свой код с помощью приведенных выше предложений, и все прошло хорошо. Все произошло именно так, как я и ожидал.

Однако проблема, с которой я столкнулся, заключалась в том, сколько времени потребовалось для запуска приложения в большой папке. (содержит 6000 файлов и 5 подпапок)

На небольшой папке (28 файлов в 5 подпапках) это заняло всего несколько секунд. Но в более крупной папке потребовалось 35 минут, чтобы обработать только 1300 файлов.

Решение:

Приведенный ниже код будет делать то же самое, но гораздо быстрее. Эта новая версия обработала 6000 файлов примерно за 10 секунд. Он обработал 40 000 файлов примерно за 1 минуту и 50 секунд.

Что этот новый код делает (и не делает)

Если папка назначения пуста, скопируйте все данные из источника в папку назначения.

Если в пункте назначения есть некоторые или все те же файлы / папки, что и в источнике, сравните и скопируйте все новые или измененные файлы из источника в пункт назначения.

Если конечный файл новее исходного, не копируйте его.

Итак, вот код, чтобы это произошло. Наслаждайтесь и делитесь.

Спасибо всем, кто помог мне лучше понять это.

using System;
    using System.IO;


    namespace VSU1vFileCopy
    {
        class Program
        {
            static void Main(string[] args)
            {
                const string Src_FOLDER = @"C:\Data";
                const string Dest_FOLDER = @"E:\Data";
                string[] originalFiles = Directory.GetFiles(Src_FOLDER, "*", SearchOption.AllDirectories);

                Array.ForEach(originalFiles, (originalFileLocation) =>
                {
                    FileInfo originalFile = new FileInfo(originalFileLocation);
                    FileInfo destFile = new FileInfo(originalFileLocation.Replace(Src_FOLDER, Dest_FOLDER));

                    if (destFile.Exists)
                    {
                        if (originalFile.Length > destFile.Length)
                        {
                            originalFile.CopyTo(destFile.FullName, true);
                        }
                    }
                    else
                    {
                        Directory.CreateDirectory(destFile.DirectoryName);
                        originalFile.CopyTo(destFile.FullName, false);
                    }
                });
            }
        }
    }


Member 14055879

Как вы игнорируете информацию о системном Томе и другие скрытые файлы и папки с помощью этого кода?

Рейтинг:
2

Patrice T

Вот справочник от одного ученого в Испании
Программы для Windows 95+ [^]
Нажмите в списке слева Сравнение Каталогов: это аккуратная маленькая утилита, которая делает то, что вы хотите, и, вероятно, больше.


Рейтинг:
0

Gerry Schmitz

Вы сравниваете только даты, а не имена файлов. (Избавьтесь от этой "внутренней петли").

Сделать .Вызов функции SingleOrDefault() для destFiles.ToList() для проверки целевого файла с заданным именем исходного файла.

Если он не находит его, он новый; в противном случае сравните даты.


Member 12969219

Ладно, это должно быть выше моего понимания. Возможно, мне придется попросить кого-то написать недостающий код для меня и объяснить, как он работает. Как я уже сказал, Я новичок в C# и мне еще многому предстоит научиться.

BillWoodruff

+5