Skip to content

Instantly share code, notes, and snippets.

@XoseLluis
Last active August 29, 2015 14:05
Show Gist options
  • Save XoseLluis/dc80792bcbf48d502dde to your computer and use it in GitHub Desktop.
Save XoseLluis/dc80792bcbf48d502dde to your computer and use it in GitHub Desktop.
Copies a file in a non locking mode, so that other processes will be able to write to it while the copy is taking place. The copy can be canceled, and events are raised each time a certaing percentage of the copy is achieved.
// deploytonenyures.blogspot.com
// example of how to use of the FileCopyTaker class
// while running the copy, you can easily try to append lines to the file with just: echo myline >> file.txt
using System;
using System.IO;
using System.Collections.Generic;
using System.Threading;
using System.Web.Script.Serialization;
class DoCopy
{
public static void Main(String[] args)
{
Console.WriteLine("Program started");
if (args.Length < 1){
Console.WriteLine("Wrong Parameters: DoCopy.exe configEntry");
System.Environment.Exit(1);
}
string configKey = args[0];
string configStr = new StreamReader("DoCopy.json").ReadToEnd();
JavaScriptSerializer configReader = new JavaScriptSerializer();
Dictionary<string, string[]> config = configReader.Deserialize<Dictionary<string, string[]>>(configStr);
if (!config.ContainsKey(configKey)){
Console.WriteLine("the key: " + configKey + " does not exist in the config file");
System.Environment.Exit(1);
}
string sourceFilePath = config[configKey][0];
string targetFilePath = config[configKey][1];
FileCopyTaker copyTaker = new FileCopyTaker(sourceFilePath, targetFilePath, 20);
copyTaker.PercentageCopied += (o, e) => {
Console.WriteLine(e.PercentageDone + "% of " + e.TotalBytes + " copied");
};
AutoResetEvent waitHandle = new AutoResetEvent(false);
copyTaker.CopyDone += (o, e) => {
Console.WriteLine("Copy completed");
waitHandle.Set();
};
Console.WriteLine("Copying: " + sourceFilePath + " to: " + targetFilePath);
Console.WriteLine("Press C to Cancel");
copyTaker.DoCopy(); //it runs in a separate thread
//Wait for the copy to be complete or for the user to cancel it
bool cancel = false;
bool copyFinished = false;
while (!cancel && !copyFinished){
copyFinished = waitHandle.WaitOne(100);
if (!copyFinished && Console.KeyAvailable){
if (Console.ReadKey().Key == ConsoleKey.C){
cancel = true;
Console.WriteLine();
copyTaker.Cancel();
}
}
}
Console.WriteLine("Program finished");
}
}
// deploytonenyures.blogspot.com
// copies a file in a non locking mode, so that other processes will be able to write to it while the copy is taking place.
// the copy can be canceled, and events are raised each time a certaing percentage of the copy is achieved.
using System;
using System.IO;
using System.Threading;
class CopyEventArgs: EventArgs
{
public int PercentageDone {get; private set;}
//this is the total Bytes that have to be copied (that is, the file of the size)
public long TotalBytes {get; private set;}
public CopyEventArgs(int percentageDone, long totalBytes)
{
this.PercentageDone = percentageDone;
this.TotalBytes = totalBytes;
}
}
class FileCopyTaker
{
public event EventHandler<CopyEventArgs> PercentageCopied;
public event EventHandler<EventArgs> CopyDone;
public event EventHandler<EventArgs> CancelDone;
private string sourceFilePath;
private string targetFilePath;
private int blockSize = 0x10000;
//each time this percentage is copied, raise the PercentageCopied event
private int percentageToNotify;
private bool cancel = false;
public FileCopyTaker(string sourceFilePath, string targetFilePath, int percentageToNotify)
{
this.sourceFilePath = sourceFilePath;
this.targetFilePath = targetFilePath;
this.percentageToNotify = (percentageToNotify > 0 && percentageToNotify < 100) ? percentageToNotify : 20;
this.PercentageCopied += (o, e) => {};
this.CopyDone += (o, e) => {};
this.CancelDone += (o, e) => {};
}
// public void Pause()
// {
//
// }
// public void Continue()
// {
//
// }
//
// public void Stop()
// {
//
// }
public void Cancel()
{
this.cancel = true;
}
public void DoCopy()
{
new Thread(() => {
int totalPercentageCopied = 0;
long sourceSize = new FileInfo(this.sourceFilePath).Length;
long bytesPerPercentageStep = sourceSize / (100/this.percentageToNotify);
long bytesCopiedForCurrentPercentageStep = 0;
using(var inputFile = new FileStream(this.sourceFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)){
using (var outputFile = new FileStream(this.targetFilePath, FileMode.Create)){
var buffer = new byte[blockSize];
int bytesRead;
while (!this.cancel && (bytesRead = inputFile.Read(buffer, 0, buffer.Length)) > 0){
outputFile.Write(buffer, 0, bytesRead);
//Thread.Sleep(100); //test, simulate latency
bytesCopiedForCurrentPercentageStep += this.blockSize;
if (bytesCopiedForCurrentPercentageStep >= bytesPerPercentageStep){
totalPercentageCopied += this.percentageToNotify;
this.PercentageCopied(this, new CopyEventArgs(totalPercentageCopied, sourceSize));
bytesCopiedForCurrentPercentageStep = 0;
}
}
if (!this.cancel){
this.CopyDone(this, new CopyEventArgs(100, sourceSize));
}
}
}
//do this outside the "using" so the FileStream has already been closed
if (this.cancel){
File.Delete(this.targetFilePath);
this.CancelDone(this, new CopyEventArgs(totalPercentageCopied, sourceSize));
}
}).Start();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment