using System;
using System.Collections;
using System.IO;
using System.Threading;
namespace AdvancedFileManager
{
public delegate void FileCopyEventHandler(object sender, FileCopyEventArgs e);
public class FileCopyEventArgs : EventArgs
{
public int Percent;
public FileCopyEventArgs(int percent)
{
Percent = percent;
}
}
public class AdvancedFileManager
{
public event FileCopyEventHandler SourceFileCopyEvent;
public event FileCopyEventHandler DestinationFileCopyEvent;
public const int BUFFER_SIZE = 1024;
public const int QUEUE_SIZE = BUFFER_SIZE * 20;
public void AsyncCopy(string source, string destination, bool overwrite)
{
// Usual verifications
if (!File.Exists(source))
{
throw new FileNotFoundException
("Source file does not exists!" );
}
if (File.Exists(destination) && !overwrite)
{
throw new Exception
("Destination file already exists but overwrite is disabled!" );
}
Queue queue =
new Queue
();
// Ajouter les messages d'erreur propre en cas de problème d'accès aux fichiers
FileProducer Prod =
new FileProducer
(queue, source
);
FileConsumer Cons =
new FileConsumer
(queue, destination, Prod.
Length);
Prod.
FileCopyEvent +=
new FileCopyEventHandler
(Prod_FileCopyEvent
);
Cons.
FileCopyEvent +=
new FileCopyEventHandler
(Cons_FileCopyEvent
);
Thread Producer =
new Thread
(new ThreadStart
(Prod.
ThreadRun));
Thread Consumer =
new Thread
(new ThreadStart
(Cons.
ThreadRun));
try
{
Producer.Start();
Consumer.Start();
Producer.Join();
Consumer.Join();
}
catch
{
throw new Exception
("Unhandled exception while running threads" );
}
}
private void Prod_FileCopyEvent(object sender, FileCopyEventArgs e)
{
OnSourceFileCopyNotification
(new FileCopyEventArgs
(e.
Percent));
}
private void Cons_FileCopyEvent(object sender, FileCopyEventArgs e)
{
OnDestinationFileCopyNotification
(new FileCopyEventArgs
(e.
Percent));
}
protected virtual void OnSourceFileCopyNotification(FileCopyEventArgs e)
{
SourceFileCopyEvent(this, e);
}
protected virtual void OnDestinationFileCopyNotification(FileCopyEventArgs e)
{
DestinationFileCopyEvent(this, e);
}
private class FileProducer
{
public double Length;
FileStream fs;
string filename;
Queue q;
int oldPercent = 0, percent = 0;
public event FileCopyEventHandler FileCopyEvent;
public FileProducer(Queue queue, string source)
{
q = queue;
filename = source;
FileInfo fi =
new FileInfo
(filename
);
Length = (double)fi.Length;
}
public void ThreadRun()
{
fs = File.OpenRead(filename);
byte[] buffer =
new byte[BUFFER_SIZE
];
int length;
while ((length = fs.Read(buffer, 0, BUFFER_SIZE)) > 0)
{
Monitor.Enter(q);
while (q.Count > QUEUE_SIZE)
{
// Wait until the consummer consume some data in the buffer
Monitor.Wait(q);
}
percent = (int)((double)fs.Position / Length * 100);
if (percent != oldPercent)
{
OnFileCopyNotification
(new FileCopyEventArgs
(percent
));
oldPercent = percent;
}
if (length < BUFFER_SIZE)
{
byte[] b =
new byte[length
];
for (int i = 0; i < length; i++)
{
b[i] = buffer[i];
}
q.Enqueue(b);
}
else
{
q.Enqueue(buffer.Clone());
}
Monitor.Pulse(q);
Monitor.Exit(q);
}
Monitor.Enter(q);
// Don't care is Queue is full, as it's the last item and it's 0-length
Monitor.Pulse(q);
Monitor.Exit(q);
fs.Close();
fs.Dispose();
}
protected virtual void OnFileCopyNotification(FileCopyEventArgs e)
{
FileCopyEvent(this, e);
}
}
private class FileConsumer
{
FileStream fd;
string filename;
Queue q;
double TotalLength;
int oldPercent = 0, percent = 0;
public event FileCopyEventHandler FileCopyEvent;
public FileConsumer(Queue queue, string destination, double sourcelength)
{
q = queue;
filename = destination;
TotalLength = sourcelength;
}
public void ThreadRun()
{
fd = File.Create(filename);
object o;
byte[] buffer;
bool Continue = true;
while (Continue)
{
Monitor.Enter(q);
if (q.Count == 0)
{
Monitor.Wait(q);
}
o = q.Dequeue();
buffer = (byte[])o;
if (buffer.Length == 0)
{
Continue = false;
}
Monitor.Pulse(q);
Monitor.Exit(q);
if (Continue)
{
fd.Write(buffer, 0, buffer.Length);
percent = (int)((double)fd.Position / TotalLength * 100);
if (percent != oldPercent)
{
OnFileCopyNotification
(new FileCopyEventArgs
(percent
));
oldPercent = percent;
}
}
}
fd.Close();
fd.Dispose();
}
protected virtual void OnFileCopyNotification(FileCopyEventArgs e)
{
FileCopyEvent(this, e);
}
}
}
}