复制文件夹,但忽略一些子文件夹

时间:2019-05-17 11:26:29

标签: c# filter directory copy

已解决,感谢戴夫的回答。

他向我展示了如何停止async任务,该任务回答了我的第二个问题。

要过滤不需要的文件夹,我已更改SkipDirectory(string)来检查目录的路径(如果您有更好的解决方案,我希望听到它)。 该函数写在底部。

我想知道C#中是否有一种复制文件夹的方法,但是带有一些过滤器。即不包括某些子文件夹。

如何在不使程序卡死的情况下执行此操作。 我发现的当前代码会复制该文件夹及其所有子文件夹,但该程序会卡住一秒钟。

我发现的另一个代码使用async方法,它解决了突然暂停的问题,但是我无法在中间停止它(必须有一个选项来停止任务)

总而言之,我需要做两件事:

1)复制一个文件夹,不包括某些子文件夹。

2)复制文件夹而不会使程序卡住

这是我使用的第一个代码(没有async):

private void Copy(string sourcePath, string destinationPath)
{
    foreach (string dirPath in Directory.GetDirectories(sourcePath, "*",
   SearchOption.AllDirectories))
    {
        if (SkipDirectory(dirPath))
        {
            continue;
        }
        Debug.Log(dirPath);
        Directory.CreateDirectory(dirPath.Replace(sourcePath, destinationPath));
    }

    //Copy all the files & Replaces any files with the same name
    foreach (string newPath in Directory.GetFiles(sourcePath, "*.*",
        SearchOption.AllDirectories))
    {
        try
        {
            FileInfo file = new FileInfo(newPath);
            if (SkipDirectory(file.DirectoryName)) continue;    
            text += ("Copying " + newPath + "\n\n");
            File.Copy(newPath, newPath.Replace(sourcePath, destinationPath), true);
        }
        catch (System.Exception)
        {

        }
    }
}

还有async代码:

private async System.Threading.Tasks.Task Copy(string startDirectory, string endDirectory)
{
    foreach (string dirPath in Directory.GetDirectories(startDirectory, "*", SearchOption.AllDirectories))
    {
        if (!SkipDirectory(dirPath))
        {
            Debug.Log("Creating directory " + dirPath);
            Directory.CreateDirectory(dirPath.Replace(startDirectory, endDirectory));
            foreach (string filename in Directory.EnumerateFiles(dirPath))
            {
                try
                {
                    using (FileStream SourceStream = File.Open(filename, FileMode.Open))
                    {
                        using (FileStream DestinationStream = File.Create(filename.Replace(startDirectory, endDirectory)))
                        {
                            text += ("Copying " + filename + "\n\n");
                            await SourceStream.CopyToAsync(DestinationStream);
                        }
                    }
                }
                catch (System.Exception e)
                {
                    Debug.LogWarning($"Inner loop:\t{filename}\t{e.Message}");
                }
            }
        }
        else
        {
            Debug.Log("Skipping " + dirPath);
        }
    }

    foreach (string filename in Directory.EnumerateFiles(startDirectory))
    {
        try
        {
            using (FileStream SourceStream = File.Open(filename, FileMode.Open))
            {
                using (FileStream DestinationStream = File.Create(endDirectory + filename.Substring(filename.LastIndexOf('\\'))))
                {

                    await SourceStream.CopyToAsync(DestinationStream);
                }
            }
        }
        catch (System.Exception e)
        {
            Debug.LogWarning($"Outter loop:\t{filename}\t{e.Message}");
        }
    }
}

SkipDirectory(string)函数仅根据文件夹名称返回true / false:

private bool SkipDirectory(string dirPath)
{
    dirPath = dirPath.ToLower();
    string[] namesToSkip = { "library", "temp", "obj", ".vs" };
    foreach (string nameToSkip in namesToSkip)
    {
        // I now check the path of the folder to see if it matches.
        string unwantedPath = $@"{projectPath}\{nameToSkip}".ToLower();
        if (dirPath.StartsWith(unwantedPath))
        {
            return true;
        }
    }
    return false;
}

1 个答案:

答案 0 :(得分:1)

因此您可以将CancellationToken传递给您的方法,并将其用于请求取消

您的代码已更新为可以使用取消令牌

private async Task Copy(string startDirectory, string endDirectory, CancellationToken ct)
{
    foreach (string dirPath in Directory.GetDirectories(startDirectory, "*", SearchOption.AllDirectories))
    {
        //Here we check if cancellation has been requesting if it has it will throw an exception (you can also check the IsCancellationRequested property and return) 
        ct.ThrowIfCancellationRequested();

        if (!SkipDirectory(dirPath))
        {
            Debug.Log("Creating directory " + dirPath);
            Directory.CreateDirectory(dirPath.Replace(startDirectory, endDirectory));
            foreach (string filename in Directory.EnumerateFiles(dirPath))
            {
                try
                {
                    using (FileStream SourceStream = File.Open(filename, FileMode.Open))
                    {
                        using (FileStream DestinationStream = File.Create(filename.Replace(startDirectory, endDirectory)))
                        {
                            await SourceStream.CopyToAsync(DestinationStream,81920, ct); //Pass cancellation token in to here and this can also handle cancellation
                        }
                    }
                }
                catch (OperationCanceledException)
                {
                    throw;
                }
                catch (System.Exception e)
                {
                    Debug.LogWarning($"Inner loop:\t{filename}\t{e.Message}");
                }
            }
        }
        else
        {
            Debug.Log("Skipping " + dirPath);
        }
    }

    foreach (string filename in Directory.EnumerateFiles(startDirectory))
    {
        //Here we check if cancellation has been requesting if it has it will throw an exception (you can also check the IsCancellationRequested property and return) 
        ct.ThrowIfCancellationRequested();
        try
        {
            using (FileStream SourceStream = File.Open(filename, FileMode.Open))
            {
                using (FileStream DestinationStream = File.Create(endDirectory + filename.Substring(filename.LastIndexOf('\\'))))
                {

                    await SourceStream.CopyToAsync(DestinationStream,81920, ct); //Pass cancellation token in to here and this can also handle cancellation
                }
            }
        }
        catch(OperationCanceledException)
        {
            throw;
        }
        catch (System.Exception e)
        {
            Debug.LogWarning($"Outter loop:\t{filename}\t{e.Message}");
        }
    }
}

然后您的代码调用者可以通过执行以下操作来创建新的取消令牌

var cts = new CancellationTokenSource(); //you can also pass a value for a timeout to this ctor var token = cts.Token;

您可以通过致电cts.Cancel()

取消