我想用c#将一个目录的全部内容从一个位置复制到另一个位置。

使用System似乎没有办法做到这一点。没有大量递归的IO类。

如果我们添加对Microsoft的引用,VB中有一个方法可以使用。VisualBasic:

new Microsoft.VisualBasic.Devices.Computer().
    FileSystem.CopyDirectory( sourceFolder, outputFolder );

这似乎是一个相当丑陋的黑客。有没有更好的办法?


当前回答

对于UWP和Winui 3 (WindowsAppSdk)使用Async API:

public async Task CopyAsync(StorageFolder source, StorageFolder dest)
{
    foreach (var item in await source.GetItemsAsync())

        if (item is StorageFile file)
            await file.CopyAsync(dest);

        else if (item is StorageFolder folder)
            await CopyAsync(folder, await dest.CreateFolderAsync(folder.Name, CreationCollisionOption.OpenIfExists));
}

其他回答

或者,如果你想走一条艰难的路,为你的微软项目添加一个引用。然后使用下面的代码:

Microsoft.VisualBasic.FileIO.FileSystem.CopyDirectory(fromDirectory, toDirectory);

然而,使用一个递归函数是一个更好的方法,因为它不需要加载VB dll。

抱歉之前的代码,它仍然有bug:((成为最快枪问题的猎物)。这里是测试和工作。键是SearchOption。AllDirectories,这消除了显式递归的需要。

string path = "C:\\a";
string[] dirs = Directory.GetDirectories(path, "*.*", SearchOption.AllDirectories);
string newpath = "C:\\x";
try
{
    Directory.CreateDirectory(newpath);
}
catch (IOException ex)
{
    Console.WriteLine(ex.Message);
}
for (int j = 0; j < dirs.Length; j++)
{
    try
    {
        Directory.CreateDirectory(dirs[j].Replace(path, newpath));
    }
    catch (IOException ex)
    {
        Console.WriteLine(ex.Message);
    }
}

string[] files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
for (int j = 0; j < files.Length; j++)            
{
    try
    {
        File.Copy(files[j], files[j].Replace(path, newpath));
    }
    catch (IOException ex)
    {
        Console.WriteLine(ex.Message);
    }
}

你可以一直使用这个,摘自微软网站。

static void Main()
{
    // Copy from the current directory, include subdirectories.
    DirectoryCopy(".", @".\temp", true);
}

private static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs)
{
    // Get the subdirectories for the specified directory.
    DirectoryInfo dir = new DirectoryInfo(sourceDirName);

    if (!dir.Exists)
    {
        throw new DirectoryNotFoundException(
            "Source directory does not exist or could not be found: "
            + sourceDirName);
    }

    DirectoryInfo[] dirs = dir.GetDirectories();
    // If the destination directory doesn't exist, create it.
    if (!Directory.Exists(destDirName))
    {
        Directory.CreateDirectory(destDirName);
    }

    // Get the files in the directory and copy them to the new location.
    FileInfo[] files = dir.GetFiles();
    foreach (FileInfo file in files)
    {
        string temppath = Path.Combine(destDirName, file.Name);
        file.CopyTo(temppath, false);
    }

    // If copying subdirectories, copy them and their contents to new location.
    if (copySubDirs)
    {
        foreach (DirectoryInfo subdir in dirs)
        {
            string temppath = Path.Combine(destDirName, subdir.Name);
            DirectoryCopy(subdir.FullName, temppath, copySubDirs);
        }
    }
}

嗯,我想我误解了这个问题,但我要冒这个险。下面这个简单的方法有什么问题?

public static void CopyFilesRecursively(DirectoryInfo source, DirectoryInfo target) {
    foreach (DirectoryInfo dir in source.GetDirectories())
        CopyFilesRecursively(dir, target.CreateSubdirectory(dir.Name));
    foreach (FileInfo file in source.GetFiles())
        file.CopyTo(Path.Combine(target.FullName, file.Name));
}

由于这篇文章为一个同样简单的问题提供了如此简单的答案,获得了令人印象深刻的反对票,让我补充一个解释。请在投反对票前阅读这篇文章。

首先,这段代码并不打算作为问题中代码的直接替换。这只是为了说明。

microsoft . visualbasic . devices . computer . filesystm . copydirectory执行一些附加的正确性测试(例如,源和目标是否为有效目录,源是否为目标的父目录等),这些测试在这个答案中是缺失的。该代码可能也更加优化了。

也就是说,代码运行良好。它(几乎完全相同)已经在一个成熟的软件中使用多年了。除了所有IO处理固有的变化无常(例如,如果用户在代码写入USB驱动器时手动拔出USB驱动器会发生什么?),没有已知的问题。

特别地,我想指出这里使用递归绝对不是问题。无论是在理论上(概念上,这是最优雅的解决方案)还是在实践中:这段代码都不会溢出堆栈。这个堆栈足够大,甚至可以处理嵌套很深的文件层次结构。早在堆栈空间成为问题之前,文件夹路径长度限制就开始生效了。

请注意,恶意用户可能会通过使用每个字母嵌套很深的目录来打破这一假设。我还没试过。但是为了说明这一点:为了使这段代码在典型的计算机上溢出,目录必须嵌套几千次。这是不现实的情况。

复制自MSDN:

using System;
using System.IO;

class CopyDir
{
    public static void Copy(string sourceDirectory, string targetDirectory)
    {
        DirectoryInfo diSource = new DirectoryInfo(sourceDirectory);
        DirectoryInfo diTarget = new DirectoryInfo(targetDirectory);

        CopyAll(diSource, diTarget);
    }

    public static void CopyAll(DirectoryInfo source, DirectoryInfo target)
    {
        Directory.CreateDirectory(target.FullName);

        // Copy each file into the new directory.
        foreach (FileInfo fi in source.GetFiles())
        {
            Console.WriteLine(@"Copying {0}\{1}", target.FullName, fi.Name);
            fi.CopyTo(Path.Combine(target.FullName, fi.Name), true);
        }

        // Copy each subdirectory using recursion.
        foreach (DirectoryInfo diSourceSubDir in source.GetDirectories())
        {
            DirectoryInfo nextTargetSubDir =
                target.CreateSubdirectory(diSourceSubDir.Name);
            CopyAll(diSourceSubDir, nextTargetSubDir);
        }
    }

    public static void Main()
    {
        string sourceDirectory = @"c:\sourceDirectory";
        string targetDirectory = @"c:\targetDirectory";

        Copy(sourceDirectory, targetDirectory);
    }

    // Output will vary based on the contents of the source directory.
}