levi
levi

Reputation: 3511

Copy Multiple Files in a Thread

I've the following scenario, I've to copy multiple (about 10,50,200,...) files. I do that syncronously one after another. This is my code snippet for that.

static void Main(string[] args)
        {
            string path = @"";
            FileSystemWatcher listener = new FileSystemWatcher(path);
            listener.Created += new FileSystemEventHandler(listener_Created);
            listener.EnableRaisingEvents = true;

            while (Console.ReadLine() != "exit") ;
        }

        public static void listener_Created(object sender, FileSystemEventArgs e)
        {
            while (!IsFileReady(e.FullPath)) ;
            File.Copy(e.FullPath, @"D:\levani\FolderListenerTest\CopiedFilesFolder\" + e.Name);
        }

So when files are created in some folder and it's ready to use I copy that file one after another, but I need to start copying as soon as any file is ready to use. So I think I should use Threads. So.. How to implement parallel copying?

@Chris

Check if file is ready

public static bool IsFileReady(String sFilename)
        {
            // If the file can be opened for exclusive access it means that the file
            // is no longer locked by another process.
            try
            {
                using (FileStream inputStream = File.Open(sFilename, FileMode.Open, FileAccess.Read, FileShare.None))
                {
                    if (inputStream.Length > 0)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }

                }
            }
            catch (Exception)
            {
                return false;
            }
        }

Upvotes: 5

Views: 5796

Answers (3)

Carl Winder
Carl Winder

Reputation: 948

You could possibly have one Thread which does all the processing i.e.

Queue files = new Queue();

static void Main(string[] args)
{
      string path = @"";
      FileSystemWatcher listener = new FileSystemWatcher(path);
      Thread t = new Thread(new ThreadStart(ProcessFiles));
      t.Start();
      listener.Created += new FileSystemEventHandler(listener_Created);
      listener.EnableRaisingEvents = true;

      while (Console.ReadLine() != "exit") ;
}


public static void listener_Created(object sender, FileSystemEventArgs e)
{
    files.Enqueue(e.FullPath);
}

void ProcessFiles()
{
    while(true)
    {
        if(files.Count > 0)
        {
              String file = files.Dequeue();
              while (!IsFileReady(file)) ;

              File.Copy(file, @"D:\levani\FolderListenerTest\CopiedFilesFolder\" +           file);
        }
    }
}

And in your listener event add the file name to a queue.

Then in your Thread you can grab the file name from the queue and do your processing from there.

Upvotes: 2

Daniel Mošmondor
Daniel Mošmondor

Reputation: 19956

Now only that (what @Tudor says), but copying files in parallel will create mess out of your hard drive, due to fragmenting. In my app, I use queued copying of 200 simultaneously previously generated files, just to put them on the hard drive in 'linear' fashion.

You can read some more on the subject here.

Upvotes: 2

Tudor
Tudor

Reputation: 62439

Doing parallel I/O from a mechanical disk is a bad idea and will only slow things down, as the mechanical head needs to spin every time to seek the next read location (a very slow process) and will then be bounced around as each thread gets its turn to run.

Stick to the sequential approach and read the files in a single thread.

Upvotes: 12

Related Questions