c# - 使用 File.Copy 时如何实现超时?

标签 c# .net file-io io timeout

我正在使用 System.IO.File.Copy 将文件从远程共享复制到本地系统。如果复制时间太长,如何实现超时?

最佳答案

例如,可以使用async-await模式来完成:

Task timeoutTask = Task.Delay(TimeSpan.FromSeconds(10));

// I use a completion source to set File.Copy thread from its own
// thread, and use it later to abort it if needed
TaskCompletionSource<Thread> copyThreadCompletionSource = new TaskCompletionSource<Thread>();

// This will await while any of both given tasks end.
await Task.WhenAny
(
    timeoutTask,
    Task.Factory.StartNew
    (
        () =>
        {
            // This will let main thread access this thread and force a Thread.Abort
            // if the operation must be canceled due to a timeout
            copyThreadCompletionSource.SetResult(Thread.CurrentThread);
            File.Copy(@"C:\x.txt", @"C:\y.txt");
        }
    )
);


// Since timeoutTask was completed before wrapped File.Copy task you can 
// consider that the operation timed out
if (timeoutTask.Status == TaskStatus.RanToCompletion)
{
    // Timed out!
    Thread copyThread = await copyThreadCompletionSource.Task;
    copyThread.Abort();
}

您可以封装它以便在需要时重新使用它:

public static class Timeout
{
    public static async Task<bool> ForAsync(Action operationWithTimeout, TimeSpan maxTime)
    {
        Contract.Requires(operationWithTimeout != null);

        Task timeoutTask = Task.Delay(maxTime);
        TaskCompletionSource<Thread> copyThreadCompletionSource = new TaskCompletionSource<Thread>();

        // This will await while any of both given tasks end.
        await Task.WhenAny
        (
            timeoutTask,
            Task.Factory.StartNew
            (
                () =>
                {
                    // This will let main thread access this thread and force a Thread.Abort
                    // if the operation must be canceled due to a timeout
                    copyThreadCompletionSource.SetResult(Thread.CurrentThread);
                    operationWithTimeout();
                }
            )
        );


        // Since timeoutTask was completed before wrapped File.Copy task you can 
        // consider that the operation timed out
        if (timeoutTask.Status == TaskStatus.RanToCompletion)
        {
            // Timed out!
            Thread copyThread = await copyThreadCompletionSource.Task;
            copyThread.Abort();

            return false;
        }
        else
        {
            return true;
        }             
    }
}

在项目中的某个地方,您可以这样调用上述方法:

bool success = await Timeout.ForAsync(() => File.Copy(...), TimeSpan.FromSeconds(10));

if(success)
{
   // Do stuff if File.Copy didn't time out!
}

请注意,我使用了 Thread.Abort() 而不是使用 CancellationToken。在您的用例中,您需要调用一个无法使用所谓的取消模式的同步方法,我相信这可能是 Thread.Abort() 可以使用的少数情况之一是一个有效的选项

最终,如果超时,代码将中止执行File.Copy的线程,因此,它应该足以停止 I/O 操作。

关于c# - 使用 File.Copy 时如何实现超时?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30681886/

相关文章:

c# - await DoSomethingAsync 有什么意义

c# - 如何使用 C# 安全连接到 MySQL,反编译时不显示任何信息

c# - LINQ Count 和 Max 一起使用

c# - skydrive System.Dynamic.DynamicObject

c# - 使用 Linq 读取 Excel 工作表

c# - 跨多个 View 共享的 ViewModel

c# - 如何确定类是否在构建或运行时用 PostSharp 方面进行修饰

java - 用户输入文件控制台/命令行 - Java

c++ - C++ 从文件中读取输入

c++ - 使用 WIN32 读取文本文件