Click here to Skip to main content
15,887,898 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I know this has probably been done and discussed umpteen times, but I can’t find the answer I am looking for.

I am trying to create a simple “directory/file copy" console application in C#. What I need is to copy all folders and files (keeping the original hierarchy) from one drive to another, like from drive C:\Data to drive E:\Data.

However, I only want it to copy any NEW or MODIFIED files from the source to the destination.
If the file on the destination drive is newer than the one on the source drive, then it does not copy.

(the problem)
In the code I have, it's comparing file "abc.pdf" in the source with file "xyz.pdf" in the destination and thus is overwriting the destination file with whatever is in the source even though the destination file is newer. I am trying to figure out how to make it compare "abc.pdf" in the source to "abc.pdf" in the destination.
This works if I drill the source and destination down to a specific file, but when I back out to the folder level, it overwrites the destination file with the source file, even though the destination file is newer.

(my solutions – that didn’t work)
I thought by putting the “if (file.LastWriteTime > destination.LastWriteTime)” after the “foreach” command, that it would compare the files in the two folders, File1 source to File1 destination, but it’s not.

It seems I’m missing something in either the “FileInfo[]”, “foreach” or “if” statements to make this a one-to-one comparison. I think maybe some reference to the “Path.Combine” statement or a “SearchOption.AllDirectories”, but I’m not sure.

Any suggestions?
As you can see from my basic code sample, I'm new to C# so please put your answer in simple terms.

Thank you.
Below is the code I have tried, but it’s not working.

What I have tried:

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));  
        }  
    }  
}  
Posted
Updated 9-Apr-19 10:22am

You're only comparing dates, not file names. (Get rid of that "inner loop").

Do a .SingleOrDefault() call on destFiles.ToList() to check for a destination file given a source file name.

If it doesn't find it, it's new; else compare the dates.
 
Share this answer
 
Comments
Member 12969219 22-Mar-19 16:21pm    
Okay, this must be over my head. I may need to get someone to write the missing code for me and explain how it works. Like I said, I am new to C# and have a lot to learn.
BillWoodruff 23-Mar-19 2:46am    
+5
After this line:
foreach (FileInfo fileD in destFiles) 
you should first compare the file names for equality, and only then do the copying:
C#
If (file.Name.equals(fileD.Name))
{
// your code ...
}
If you want something more advanced you could try Gerry's solution which involves using LINQ.
 
Share this answer
 
v2
Comments
Member 12969219 22-Mar-19 16:19pm    
Okay, I thought by getting the "FileInfo" I was getting the file name and modification date because I can print the file details in a "Console.WriteLine".
Member 12969219 22-Mar-19 17:42pm    
Oh my gosh. It works! Thank you so much. That's the command I was looking for but didn't know it existed. A great way to end the week.
BillWoodruff 23-Mar-19 2:45am    
+5
Update:

I modified my code with the suggestions above and all went well. It did exactly as I expected.

However, the problem I ran into was the amount of time it took to run the application on a large folder. (containing 6,000 files and 5 sub-folders)

On a small folder, (28 files in 5 sub-folders) it only took a few seconds to run. But, on the larger folder it took 35 minutes to process only 1,300 files.

Solution:

The code below will do the same thing but much faster. This new version processed 6,000 files in about 10 seconds. It processed 40,000 files in about 1 minute and 50 seconds.

What this new code does (and doesn’t do)

If the destination folder is empty, copy all from the source to the destination.

If the destination has some or all of the same files / folders as the source, compare and copy any new or modified files from the source to the destination.

If the destination file is newer than the source, don’t copy.

So, here’s the code to make it happen. Enjoy and share.

Thanks to everyone who helped me get a better understanding of this.

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);
                    }
                });
            }
        }
    }
 
Share this answer
 
Comments
Member 14055879 20-Oct-19 8:26am    
How do you ignore System Volume Information and other hidden files and folders with this code?
Here is a directory from an academic in Spain
Windows 95+ programs[^]
Click in list on left Directory Compare: it is a neat little utility that do what you want and probably more.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900