You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

C#中如何暂停自定义文件复制方法(无需对话框暂停按钮)

实现无需对话框按钮的文件复制暂停功能

嘿,这个需求完全可行!我们可以借助.NET里的同步原语来实现无UI触发的暂停/恢复逻辑,不用依赖对话框按钮。下面给你两种常用的实现方案,按需选择:

方案一:基于ManualResetEventSlim的暂停/恢复(推荐)

这个方案支持临时暂停复制,之后还能从暂停的位置继续,非常适合你的场景:

1. 修改复制方法,加入暂停控制逻辑

首先定义一个用于控制暂停的信号对象,然后在复制循环的关键节点检查暂停状态:

// 定义暂停信号,初始状态为"不暂停"(Set状态)
private static ManualResetEventSlim _pauseSignal = new ManualResetEventSlim(true);

public static void CopyFileInDirectory(string source, string dest, ThreadFinishedCallback callback)
{
    Threadfinished = callback;
    Directory.CreateDirectory(dest);

    foreach (string sourceFile in Directory.GetFiles(source))
    {
        // 检查是否需要暂停:如果信号被重置,线程会阻塞在这里,直到信号被再次设置
        _pauseSignal.Wait();

        try
        {
            string destFile = Path.Combine(dest, Path.GetFileName(sourceFile));
            
            // 如果你需要复制大文件时也能及时响应暂停,建议用下面的分块复制方法替代File.Copy
            // CopyFileWithPauseSupport(sourceFile, destFile, _pauseSignal);
            
            // 普通复制(小文件适用)
            File.Copy(sourceFile, destFile, overwrite: true);

            // 复制完成后再检查一次,避免后续迭代跳过暂停
            _pauseSignal.Wait();
        }
        catch (Exception ex)
        {
            // 根据你的需求处理异常,比如记录日志
            Console.WriteLine($"复制文件 {sourceFile} 失败:{ex.Message}");
        }
    }

    callback?.Invoke();
}

2. 大文件适配的分块复制方法

如果要复制大文件,File.Copy是一次性阻塞操作,无法中途响应暂停。可以替换成自定义的分块复制,在每次读写块之间检查暂停信号:

private static void CopyFileWithPauseSupport(string sourcePath, string destPath, ManualResetEventSlim pauseSignal)
{
    const int bufferSize = 4096; // 4KB块大小,可根据需要调整
    using (var sourceStream = new FileStream(sourcePath, FileMode.Open, FileAccess.Read))
    using (var destStream = new FileStream(destPath, FileMode.Create, FileAccess.Write))
    {
        byte[] buffer = new byte[bufferSize];
        int bytesRead;

        while ((bytesRead = sourceStream.Read(buffer, 0, bufferSize)) > 0)
        {
            // 读取后检查暂停
            pauseSignal.Wait();
            destStream.Write(buffer, 0, bytesRead);
            // 写入后再次检查暂停
            pauseSignal.Wait();
        }
    }
}

3. 外部触发暂停/恢复

你可以在任何地方(比如其他线程、定时任务、快捷键事件等)调用以下代码来控制复制:

// 触发暂停:重置信号,复制线程会在下次检查时阻塞
_pauseSignal.Reset();

// 恢复复制:设置信号,阻塞的线程会继续执行
_pauseSignal.Set();

方案二:基于CancellationToken的终止操作(如果需要终止而非暂停)

如果你的需求是终止复制(不是暂停后恢复),可以用CancellationToken来实现:

public static void CopyFileInDirectory(string source, string dest, ThreadFinishedCallback callback, CancellationToken cancellationToken)
{
    Threadfinished = callback;
    Directory.CreateDirectory(dest);

    foreach (string sourceFile in Directory.GetFiles(source))
    {
        // 检查是否收到终止信号,若收到则抛出异常终止操作
        cancellationToken.ThrowIfCancellationRequested();

        try
        {
            string destFile = Path.Combine(dest, Path.GetFileName(sourceFile));
            File.Copy(sourceFile, destFile, overwrite: true);
            
            cancellationToken.ThrowIfCancellationRequested();
        }
        catch (OperationCanceledException)
        {
            // 处理终止逻辑,比如清理临时文件
            Console.WriteLine("复制操作已被终止");
            throw; // 向上传递异常,让调用者处理
        }
        catch (Exception ex)
        {
            Console.WriteLine($"复制文件失败:{ex.Message}");
        }
    }

    callback?.Invoke();
}

外部可以通过CancellationTokenSource来触发终止:

var cts = new CancellationTokenSource();
// 启动复制线程
Task.Run(() => CopyFileInDirectory(sourceDir, destDir, callback, cts.Token));

// 触发终止
cts.Cancel();

内容的提问来源于stack exchange,提问作者Pierre-Olivier Morin

火山引擎 最新活动