JD Roberson
JD Roberson

Reputation: 599

Copy same file from multiple threads to multiple destinations

I am trying to write an application that copies and installer I created over to a list of computers provided. It works perfect with only one computer name in the input but when I add two or more it tells me it cannot read from the source file because its in use.

UPDATE: I am open to other methods of getting this done if this is just a lost cause. My end goal is to simply copy the same file to 500 computers in a datacenter as fast as possible. Then execute the file on each of those computers. Right now for the execution I am using psexec -s so I can bypass UAC.

/*Button Click Code Below*/
/*Install for specific OS*/
foreach (string line in txtServers.Lines)
{
    machine = line;
    lbOutput.Items.Add("Preparing to copy files....");

    /*Copy Files*/
    if(!tWorker.IsAlive)
         tWorker.Start();

    lbOutput.Items.Add("File Copy Complete! Executing installer....");
}

/*File Copy Code Below*/
try
{
   File.Copy("Ionic.Zip.Reduced.dll",@"\\"+machine+@"\C$\Temp\Ionic.Zip.Reduced.dll",true);
   File.Copy("v5.32bit.Install.exe", @"\\" + machine + @"\C$\Temp\v5.32bit.Install.exe", true);
}
catch (Exception ee)
{
   MessageBox.Show(ee.Message);
}

Upvotes: 4

Views: 1947

Answers (4)

JD Roberson
JD Roberson

Reputation: 599

Ok so after an evening of intense frustration it seems I just needed some sleep to figure this out.

I had originally done my foreach in the button click event and since I was starting a thread in that foreach it just continued regardless of the status of everything else. I have since moved that foreach to the thread and the problem was resolved. I can now copy to multiple locations at once and I must say its pretty fast.

Thanks to everyone for their help as always!

Upvotes: 1

Jim Mischel
Jim Mischel

Reputation: 134105

You might be able to do this by calling CopyFileEx, if you don't specify the COPY_FILE_OPEN_SOURCE_FOR_WRITE flag.

I published a C# wrapper for CopyFileEx a couple of years ago. See A better File.Copy replacement. I don't know if it will do what you want (allow the file to be opened by multiple threads), but it's probably worth a shot.

Upvotes: 0

Keith Nicholas
Keith Nicholas

Reputation: 44316

Another way to approach this is to cache the files in memory....

something like

  var filesToLoad = new[] {"a.txt", "b.txt"}.ToList();
  var files = new Dictionary<string, byte[]>();
  filesToLoad.ForEach(f => files.Add(f, File.ReadAllBytes(f)))

then when you want to write them

files.Keys.ToList()
   .ForEach(f => File.WriteAllBytes(Path.Combine(machinePath, f), files[f]));

Upvotes: 3

Fabian Bigler
Fabian Bigler

Reputation: 10915

The magic word is FileShare.Read:

  using(var inputFile = new FileStream(
         "oldFileName.txt", 
         FileMode.Open, 
         FileAccess.Read, 
         FileShare.Read))
     {
        using (var outputFile = new FileStream("newFileName.txt", FileMode.Create))
        { 
            var buffer = new byte[0x10000];
            int bytes;

            while ((bytes = inputFile.Read(buffer, 0, buffer.Length)) > 0) 
            {
                outputFile.Write(buffer, 0, bytes);
            }
        }
    }

Then you should be able to copy it even with multiple threads.

Upvotes: 5

Related Questions