Featured image of post 如何在 C# 中拷贝一个文件夹

如何在 C# 中拷贝一个文件夹

本文介绍了三种在 C# 中拷贝文件夹的方法,分别是使用递归、不使用递归、以及使用 VisualBasic 的内置方法。这三种方法各有优劣,读者可以根据自己的需求来选择适合的方法。

拷贝文件夹听起来是一个非常简单的任务,但是在 C# 中实现起来却并不是那么容易,因为 .NET 并没有提供内置的方法,所以通常我们只能自己来实现。

本文提供了三种拷贝文件夹的方式供大家参考。

方法一:使用递归

使用递归是一个非常直观的方法,同时也是 Microsoft Learn 给出的示例。其原版的代码有些冗余和不必要的内存开销,所以这里贴一个相对简练且高效的版本:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
static void CopyDirectory(string sourceFolderPath, string targetFolderPath)
{
    Directory.CreateDirectory(targetFolderPath);

    foreach (string filePath in Directory.GetFiles(sourceFolderPath))
    {
        string fileName = Path.GetFileName(filePath);
        string destinationPath = Path.Combine(targetFolderPath, fileName);
        File.Copy(filePath, destinationPath, true);
    }

    foreach (string directoryPath in Directory.GetDirectories(sourceFolderPath))
    {
        string directoryName = Path.GetFileName(directoryPath);
        string destinationPath = Path.Combine(targetFolderPath, directoryName);
        CopyDirectory(directoryPath, destinationPath);
    }
}

简单来说,这个方法会递归地拷贝源文件夹下的所有文件和子文件夹到目标文件夹中。对于子文件夹,会递归调用该方法进行拷贝。

Tip
Directory.CreateDirectory 是一个相当灵活的方法。如果目标文件夹不存在,它会自动创建;如果目标文件夹已经存在,它会忽略这个操作。同时,它还会沿途创建所有不存在的文件夹(类似 mkdir-p 参数)。

方法二:不使用递归

如果不希望使用递归,那么也可以通过相对路径的方式来实现。这个方法会递归搜索源文件夹下的所有文件,通过计算它与源文件夹的相对路径来得到它的目标路径,进而生成目标路径所在的文件夹。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
static void CopyDirectory(string sourceFolderPath, string targetFolderPath)
{
    Directory.CreateDirectory(targetFolderPath);

    foreach (string filePath in Directory.GetFiles(sourceFolderPath, "*.*", SearchOption.AllDirectories))
    {
        var relativePath = Path.GetRelativePath(sourceFolderPath, filePath);
        var targetFilePath = Path.Combine(targetFolderPath, relativePath);
        var subTargetFolderPath = Path.GetDirectoryName(targetFilePath);
        if (subTargetFolderPath != null)
            Directory.CreateDirectory(subTargetFolderPath);
        File.Copy(filePath, targetFilePath);
    }
}
Tip
Path.GetDirectoryName 方法有可能返回空。这一情况通常发生在文件位于根目录的情况(例如 Windows 的 C:\,或 Unix 的 /)。

使用 VisualBasic 的内置方法

其实 .NET 也不是完全没有提供内置的方法。比如我们可以使用 VisualBasic 的 Microsoft.VisualBasic.Devices 命名空间下的 Computer 类上的 FileSystem 成员的方法来实现拷贝文件夹的功能:

1
2
3
4
5
6
7
8
using Microsoft.VisualBasic.Devices;
using Microsoft.VisualBasic.FileIO;

static void CopyDirectory(string sourceFolderPath, string targetFolderPath)
{
    fs = new Computer().FileSystem;
    fs.CopyDirectory(sourceFolderPath, targetFolderPath, UIOption.OnlyErrorDialogs);
}

可能有读者想说,作者你怎么不早点拿出这个方法呢?这方法多么地简单易用啊!

实际上,这个方法也是有显著缺点的:需要使用 WinForms 相关的库。也就是说,你的项目需要 TargetFramework 包含 -windows,并且还要 UseWindowsForms

如果你在开发 WPF 或 WinForms 程序,那么这通常是可以接受的。但如果你是在开发控制台程序、ASP.NET 程序,又或者 Avalonia UI 等跨平台框架,那么这个方法显然就有些 unacceptable 了。

Tip
其实 VisualBasic 还提供了一些别的实用功能,比如将文件移至回收站,就可以用 FileSystem.DeleteFile 方法,并添加 RecycleOption.SendToRecycleBin 参数来实现。这个方法会将文件移至回收站,而不是直接删除。

总结

本文介绍了三种拷贝文件夹的方法,分别是使用递归、不使用递归、以及使用 VisualBasic 的内置方法。这三种方法各有优劣,读者可以根据自己的需求来选择适合的方法。

Warning
在拷贝文件夹时,一定要注意文件夹的权限问题。如果源文件夹或目标文件夹的权限不足,那么拷贝操作可能会失败。
使用 Hugo 构建
主题 StackJimmy 设计