首先,您需要“检测”异步执行过程中抛出的异常。这可以通过以下方式完成:
try
{
await sourceStream.CopyToAsync(destStream);
}
catch (Exception copyException)
{
}
一旦检测到并正确处理了异常,即您决定某个特定异常是重试的原因,您将必须维护自己的复制目标(和目的地)队列,以便重试。
然后,您将不得不组织一个新的入口点,该入口点会导致重试。这样的入口点可以由您使用的文件系统监视器中的计时器或下一个事件触发(我不推荐)。您还必须针对多次失败的情况实施队列溢出检测。请记住,这种溢出检测也存在于文件系统监视器中,如果系统事件太多(似乎一次将许多文件复制到受监视的文件夹中),它可以简单地跳过通知。
如果这些问题不会打扰您,我建议您实现计时器或更准确地说是超时,以便重试复制任务。另一方面,如果您需要一个强大的解决方案,我会自己实现一个文件系统监视器。
关于超时,它可能如下所示:
private Queue<myCopyTask> queue;
private Timer retryTimeout;
public Program()
{
retryTimeout = new Timer(QueueProcess, null, Timeout.Infinite, Timeout.Infinite);
}
private void FileSystemMonitorEventhandler()
{
//New tasks are provided by the file system monitor.
myCopyTask newTask = new myCopyTask();
newTask.sourcePath = "...";
newTask.destinationPath = "...";
//Keep in mind that queue is touched from different threads.
lock (queue)
{
queue.Enqueue(newTask);
}
//Keep in mind that Timer is touched from different threads.
lock (retryTimeout)
{
retryTimeout.Change(1000, Timeout.Infinite);
}
}
//Start this routine only via Timer.
private void QueueProcess(object iTimeoutState)
{
myCopyTask task = null;
do
{
//Keep in mind that queue is touched from different threads.
lock (queue)
{
if (queue.Count > 0)
{
task = queue.Dequeue();
}
}
if (task != null)
{
CopyTaskProcess(task);
}
} while (task != null);
}
private async void CopyTaskProcess(myCopyTask task)
{
FileStream sourceStream = null;
FileStream destStream = null;
try
{
sourceStream = File.OpenRead(task.sourcePath);
destStream = File.OpenWrite(task.destinationPath);
await sourceStream.CopyToAsync(destStream);
}
catch (Exception copyException)
{
task.retryCount++;
//In order to avoid instant retries on several problematic tasks you probably
//should involve a mechanism to delay retries. Keep in mind that this approach
//delays worker thread that is implicitly involved by await keyword.
Thread.Sleep(100);
//Keep in mind that queue is touched from different threads.
lock (queue)
{
queue.Enqueue(task);
}
//Keep in mind that Timer is touched from different threads.
lock (retryTimeout)
{
retryTimeout.Change(1000, Timeout.Infinite);
}
}
finally
{
if (sourceStream != null)
{
sourceStream.Close();
}
if (destStream != null)
{
destStream.Close();
}
}
}
}
internal class myCopyTask
{
public string sourcePath;
public string destinationPath;
public long retryCount;
}