Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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);
}
like image 853
JD Roberson Avatar asked Sep 11 '25 20:09

JD Roberson


2 Answers

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.

like image 60
Fabian Bigler Avatar answered Sep 13 '25 11:09

Fabian Bigler


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]));
like image 26
Keith Nicholas Avatar answered Sep 13 '25 09:09

Keith Nicholas