是否可以在不等待结果的情况下“启动”(大)文件的副本?

时间:2016-12-12 16:29:10

标签: c# asynchronous task-parallel-library xcopy

我认为这在标题中非常明显;我想复制文件而不等待结果。

功能我想要这个:

:set nopaste

基本上我的主线程在几毫秒后被释放。 我尝试这样做:

    static void Main(string[] args)
    {
        string strCmdText = @"/C xcopy c:\users\florian\desktop\mytestfile.fil p:\";
        System.Diagnostics.Process.Start("CMD.exe", strCmdText);
        Console.WriteLine("Finished !");
    }

我的mytestfile.fil是在我的目标文件夹中创建的,但其大小为0kb。

此致

4 个答案:

答案 0 :(得分:5)

  

基本上我的主线程在几毫秒后被释放。我试着这样做

你必须以某种方式让这个过程保持活力。最简单的方法 - 如果你真的必须在自己的线程上进行文件复制 - 就是在前台线程上执行你的Copy方法:

class Program
{
    static void Main(string[] args)
    {
        System.Threading.Thread thread = new System.Threading.Thread(()=> Copy(@"c:\Users\florian\Desktop\mytestfile.fil", "p:"));
        thread.Start();
    }

    private static void Copy(string source, string destination)
    {
        using (FileStream SourceStream = File.Open(source, FileMode.Open))
        {
            using (FileStream DestinationStream = File.Create(destination + source.Substring(source.LastIndexOf('\\'))))
            {
                SourceStream.CopyTo(DestinationStream);
            }
        }
    }
}

...或者您可以在主线程上执行它,因为您的应用程序似乎没有其他任何东西:

class Program
{
    static void Main(string[] args)
    {
        string source = @"c:\Users\florian\Desktop\mytestfile.fil";
        string destination = "p";
        using (FileStream SourceStream = File.Open(source, FileMode.Open))
        {
            using (FileStream DestinationStream = File.Create(destination + source.Substring(source.LastIndexOf('\\'))))
            {
                SourceStream.CopyTo(DestinationStream);
            }
        }
    }
}

第三个选项是使您的方法异步并等待它在Main方法中同步完成:

class Program
{
    static void Main(string[] args)
    {
        CopyAsync(@"c:\Users\florian\Desktop\mytestfile.fil", "p:").Wait();
    }

    private static async Task CopyAsync(string source, string destination)
    {
        using (FileStream SourceStream = File.Open(source, FileMode.Open))
        {
            using (FileStream DestinationStream = File.Create(destination + source.Substring(source.LastIndexOf('\\'))))
            {
                await SourceStream.CopyToAsync(DestinationStream);
            }
        }
    }
}

请注意,除非您正在等待它,否则不应使用异步CopyToAsync方法。不要混用同步和异步代码:)

答案 1 :(得分:4)

确定不止一个错误。

  • 您的程序在复制完成之前退出。你需要这样的东西:
  • 未等待CopyToAsync

    class Program
    {
        private static void Main(string[] args)
        {
            var source = new CancellationTokenSource();
            Console.CancelKeyPress += (s, e) =>
            {
                e.Cancel = true;
                source.Cancel();
            };
    
        try
        {
            MainAsync(args, source.Token).GetAwaiter().GetResult();
            return;
        }
        catch (OperationCanceledException)
        {
            return;
        }
    }
    
    static async Task MainAsync(string[] args, CancellationToken token)
    {
        var t = Task.Run(() => Copy(@"c:\test.txt", @"c:\dest\"));
        Console.WriteLine("doing more stuff while copying");
        await t;
        Console.WriteLine("Finished !");
    }
    
    private static void Copy(string source, string destination)
    {
        using (FileStream SourceStream = File.Open(source, FileMode.Open))
        {
            using (FileStream DestinationStream = File.Create(destination + source.Substring(source.LastIndexOf('\\'))))
            {
                SourceStream.CopyTo(DestinationStream);
            }
        }
    }
    

    }

答案 2 :(得分:1)

您的Main方法在任务完成之前返回,因此您的应用程序结束。

答案 3 :(得分:1)

似乎这可能是XY problem的一个实例。

请记住,操作系统/框架基本上是为您的进程提供了自己的“空间”来运行,所以:

static void Main(string[] args)
{
    var t = Task.Run(() => Copy(@"c:\Users\florian\Desktop\mytestfile.fil", "p:"));
}

private static void Copy(string source, string destination)
{
    using (FileStream SourceStream = File.Open(source, FileMode.Open))
    {
        using (FileStream DestinationStream = File.Create(destination + source.Substring(source.LastIndexOf('\\'))))
        {
            SourceStream.CopyToAsync(DestinationStream);
        }
    }
}

在性能方面没有什么不同于

static void Main(string[] args)
{
    Copy(@"c:\Users\florian\Desktop\mytestfile.fil", "p:");
}

由于您的控制台应用程序基本上没有执行除复制文件之外的任何操作,因此额外的线程只会增加开销。

另外,如果您在Copy方法中使用异步操作,则应该声明方法async Task而不是void,否则您无法在{}}内使用await关键字Copy方法或等待Copy方法在代码中的其他位置完成。所以:

private static async Task Copy(string source, string destination)

正如所写,这有一个明显的竞争条件,可能无法正常工作,因为DestinationStreamSourceStream可能会在SourceStream.CopyToAsync(DestinationStream)实际完成之前被处理掉。你需要做

await SourceStream.CopyToAsync(DestinationStream);

在你的方法中防止这种情况。

如果您使用

启动复制操作
System.Diagnostics.Process.Start(...);

从启动它的程序的角度来看,你已经有效地异步运行它,因为启动它的程序不会等待进程在继续之前完成。顺便说一句,我假设控制台应用程序除了启动进程之外还会执行其他操作,对吗? (如果没有,似乎有点多余)。