Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/313.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 当一个文件正在工作时,如何暂停多文件复制?_C#_Forms_Winforms - Fatal编程技术网

C# 当一个文件正在工作时,如何暂停多文件复制?

C# 当一个文件正在工作时,如何暂停多文件复制?,c#,forms,winforms,C#,Forms,Winforms,我开始了一个有趣的小项目,我非常喜欢它,我开始扩展它。我需要一个简单的文件浏览器(如windows one)来查看和打开文件,但现在扩展它时,我遇到了多个文件的问题,我想从目录A复制一些文件并将它们粘贴到B中,然后在执行此操作时,我想从目录C复制一些文件并将它们粘贴到D中,如果复制A->B正在进行,复制C->D将暂停,当复制A->B完成时,第二次复制可以开始。现在,我可以将文件从A复制到B。有没有不太复杂的东西我可以试试 我正在使用一个新表单来显示开始复制时的进度条、文件名、文件计数和大小,我正

我开始了一个有趣的小项目,我非常喜欢它,我开始扩展它。我需要一个简单的文件浏览器(如windows one)来查看和打开文件,但现在扩展它时,我遇到了多个文件的问题,我想从目录A复制一些文件并将它们粘贴到B中,然后在执行此操作时,我想从目录C复制一些文件并将它们粘贴到D中,如果复制A->B正在进行,复制C->D将暂停,当复制A->B完成时,第二次复制可以开始。现在,我可以将文件从A复制到B。有没有不太复杂的东西我可以试试


我正在使用一个新表单来显示开始复制时的进度条、文件名、文件计数和大小,我正在使用BackgroundWorker

我假设您只是在调用
file.Move
file.copy
如果无法暂停实际操作,您必须编写自己的移动/复制操作

要复制该文件,您可以执行以下操作

public void CopyFile(string sourceFileName, string destFileName, bool overwrite)
{
    var outputFileMode = overwrite ? FileMode.Create : FileMode.CreateNew;

    using (var inputStream = new FileStream(sourceFileName, FileMode.Open, FileAccess.Read, FileShare.Read))
    using (var outputStream = new FileStream(destFileName, outputFileMode, FileAccess.Write, FileShare.None))
    {
        const int bufferSize = 16384; // 16 Kb
        var buffer = new byte[bufferSize];

        int bytesRead;

        do
        {
            bytesRead = inputStream.Read(buffer, 0, bufferSize);
            outputStream.Write(buffer, 0, bytesRead);
        } while (bytesRead == bufferSize);
    }
}
现在您已经有了这个代码,您可以简单地添加一个
while
循环,并附带一个“暂停”代码的条件

while (_pause)
{
    Thread.Sleep(100);
}
while
将从上述代码进入
do
循环

这里是完整的想法

public void CopyFile(string sourceFileName, string destFileName, bool overwrite)
{
    var outputFileMode = overwrite ? FileMode.Create : FileMode.CreateNew;

    using (var inputStream = new FileStream(sourceFileName, FileMode.Open, FileAccess.Read, FileShare.Read))
    using (var outputStream = new FileStream(destFileName, outputFileMode, FileAccess.Write, FileShare.None))
    {
        const int bufferSize = 16384; // 16 Kb
        var buffer = new byte[bufferSize];

        int bytesRead;

        do
        {

            //run this loop until _pause = false
            while (_pause)
            {
                Thread.Sleep(100);
            }


            bytesRead = inputStream.Read(buffer, 0, bufferSize);
            outputStream.Write(buffer, 0, bytesRead);
        } while (bytesRead == bufferSize);
    }
}

您可以使用对象来表示不同的操作,例如

public interface IFileOperation {
    void Execute(Func<double> ReportProgress, CancellationToken cancel);
}
公共接口操作{
作废执行(Func ReportProgress、CancellationToken cancel);
}
然后,您可以创建一个包含多个操作的队列,并在另一个线程上创建一个任务来处理每个项目

private CancellationTokenSource cts = new CancellationTokenSource();
public double CurrentProgress {get; private set;}
public void CancelCurrentOperation() => cts.Cancel();
public BlockingCollection<IFileOperation> Queue = new BlockingCollection<IFileOperation>(new ConcurrentQueue<IFileOperation>());
public void RunOnWorkerThread(){
     foreach(var op in Queue .GetConsumingEnumerable()){
         cts  = new CancellationTokenSource();
         CurrentProgress  = 0;
          op.Execute(p => Progress = p, cts.Token );
     }
} 
private CancellationTokenSource cts=new CancellationTokenSource();
公共双CurrentProgress{get;private set;}
public void CancelCurrentOperation()=>cts.Cancel();
public BlockingCollection Queue=new BlockingCollection(new ConcurrentQueue());
公共无效RunOnWorkerThread(){
foreach(队列中的var op.GetConsumingEnumerable()){
cts=新的CancellationTokenSource();
当前进度=0;
op.Execute(p=>Progress=p,cts.Token);
}
} 
这将在后台线程上一次运行一个文件操作,同时允许从主线程添加新操作。要报告进度,您需要一个非模式进度条。也就是说,您不应该显示对话框,而应该在UI中的某个位置添加进度条控件。否则,如果不取消当前操作,您将无法添加新操作。您还需要某种方法将进度条连接到当前正在运行的操作,例如,在主线程上运行计时器,更新进度条绑定到的属性。您可以将该方法作为长时间运行的任务运行,也可以作为专用线程运行


如果愿意,您可以在文件操作中添加暂停/恢复方法。Rand Random的答案显示了如何手动复制文件,因此我将跳过这里。您还可以创建一个UI,该UI将显示所有排队文件操作的列表,并允许删除排队任务。您甚至可以通过更多的工作并行运行多个操作,并为每个操作显示单独的进度。

实际问题是什么?如何对操作进行排队,以便一次只运行一个操作?@JonasH是的,可能还有如何正确处理要复制的文件的历史记录。目前,我所做的最好的事情是在列表中添加完整路径(w/filename),当我粘贴时,我使用filestream并使用列表复制文件,但我确信这不是处理历史记录的最佳方法“我假设您只是调用File.Move或File.copy”否,filestream。昨天换了,因为好多了。while(_pause)_pause是如何设置的?
_pause
只是一个在点击按钮时必须设置的字段,因为我在完成复制时关闭了进度条表单,我可以使用Worker\u RunWorkerCompleter=>_pause=false(顺便说一句,我不会使用这个代码)我给了你一个大概的想法,如果你想有一个100%的解决方案,你只需要复制和粘贴,我想说我需要更多的信息,你目前正在做的事情,因为我对你的代码知之甚少,我无法告诉你如何/在哪里调用它,我需要一个更好的方法来处理历史文件,但是。。。我有一个progressbarwindow窗体,当我在上下文菜单中单击“复制”时,它会将完整的文件路径保存在一个列表中,然后在“粘贴”中执行“新建progressbarwindow”(itemsToCopy//List,fileFolder//source。我稍后删除文件名filePath.Text,false//overwrite);我可以把代码发送到某个地方,我不知道在这里怎么做。另外,你的[input/output]流不工作,进度条永远不会更新,也不会写入内容,我不需要暂停/恢复(目前)。我有一个用于进度条的表单,但看起来这是一个坏选项,我可以删除它并将进度条添加到主表单中,我需要找到如何实现所有内容correctly@code9这个问题有点宽泛。Rand Random演示了如何手动复制文件。这个答案显示了如何对后台处理的操作进行排队。如果你特别问如何创建一个非模态进度条,我建议你发布一个新问题,或者你自己尝试一下,如果你被卡住了,问一个问题