我想用c#将一个目录的全部内容从一个位置复制到另一个位置。
使用System似乎没有办法做到这一点。没有大量递归的IO类。
如果我们添加对Microsoft的引用,VB中有一个方法可以使用。VisualBasic:
new Microsoft.VisualBasic.Devices.Computer().
FileSystem.CopyDirectory( sourceFolder, outputFolder );
这似乎是一个相当丑陋的黑客。有没有更好的办法?
我想用c#将一个目录的全部内容从一个位置复制到另一个位置。
使用System似乎没有办法做到这一点。没有大量递归的IO类。
如果我们添加对Microsoft的引用,VB中有一个方法可以使用。VisualBasic:
new Microsoft.VisualBasic.Devices.Computer().
FileSystem.CopyDirectory( sourceFolder, outputFolder );
这似乎是一个相当丑陋的黑客。有没有更好的办法?
当前回答
复制自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.
}
其他回答
它可能没有性能意识,但我用它来处理30MB的文件夹,它工作得完美无缺。另外,我不喜欢这么简单的任务所需要的大量代码和递归。
var src = "c:\src";
var dest = "c:\dest";
var cmp = CompressionLevel.NoCompression;
var zip = source_folder + ".zip";
ZipFile.CreateFromDirectory(src, zip, cmp, includeBaseDirectory: false);
ZipFile.ExtractToDirectory(zip, dest_folder);
File.Delete(zip);
注意:ZipFile可以在。net 4.5+的System.IO.Compression命名空间中使用
抱歉之前的代码,它仍然有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);
}
}
对于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));
}
这段代码的属性:
没有并行任务,性能较差,但其思想是逐文件处理,因此可以记录或停止。 可以跳过隐藏文件 可以跳过修改日期吗 可以打破或不(您选择)对文件复制错误 SMB和FileShare使用64K的Buffer。读写避免锁 个性化您的异常消息 对于Windows
笔记 ExceptionToString()是一个个人扩展,试图获得内部异常和显示堆栈。将其替换为ex.Message或任何其他代码。 log4net。ILog _log我使用==Log4net==您可以用不同的方式创建您的日志。
/// <summary>
/// Recursive Directory Copy
/// </summary>
/// <param name="fromPath"></param>
/// <param name="toPath"></param>
/// <param name="continueOnException">on error, continue to copy next file</param>
/// <param name="skipHiddenFiles">To avoid files like thumbs.db</param>
/// <param name="skipByModifiedDate">Does not copy if the destiny file has the same or more recent modified date</param>
/// <remarks>
/// </remarks>
public static void CopyEntireDirectory(string fromPath, string toPath, bool continueOnException = false, bool skipHiddenFiles = true, bool skipByModifiedDate = true)
{
log4net.ILog _log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
string nl = Environment.NewLine;
string sourcePath = "";
string destPath = "";
string _exMsg = "";
void TreateException(Exception ex)
{
_log.Warn(_exMsg);
if (continueOnException == false)
{
throw new Exception($"{_exMsg}{nl}----{nl}{ex.ExceptionToString()}");
}
}
try
{
foreach (string fileName in Directory.GetFileSystemEntries(fromPath, "*", SearchOption.AllDirectories))
{
sourcePath = fileName;
destPath = Regex.Replace(fileName, "^" + Regex.Escape(fromPath), toPath);
Directory.CreateDirectory(Path.GetDirectoryName(destPath));
_log.Debug(FileCopyStream(sourcePath, destPath,skipHiddenFiles,skipByModifiedDate));
}
}
// Directory must be less than 148 characters, File must be less than 261 characters
catch (PathTooLongException)
{
throw new Exception($"Both paths must be less than 148 characters:{nl}{sourcePath}{nl}{destPath}");
}
// Not enough disk space. Cancel further copies
catch (IOException ex) when ((ex.HResult & 0xFFFF) == 0x27 || (ex.HResult & 0xFFFF) == 0x70)
{
throw new Exception($"Not enough disk space:{nl}'{toPath}'");
}
// used by another process
catch (IOException ex) when ((uint)ex.HResult == 0x80070020)
{
_exMsg = $"File is being used by another process:{nl}'{destPath}'{nl}{ex.Message}";
TreateException(ex);
}
catch (UnauthorizedAccessException ex)
{
_exMsg = $"Unauthorized Access Exception:{nl}from:'{sourcePath}'{nl}to:{destPath}";
TreateException(ex);
}
catch (Exception ex)
{
_exMsg = $"from:'{sourcePath}'{nl}to:{destPath}";
TreateException(ex);
}
}
/// <summary>
/// File Copy using Stream 64K and trying to avoid locks with fileshare
/// </summary>
/// <param name="sourcePath"></param>
/// <param name="destPath"></param>
/// <param name="skipHiddenFiles">To avoid files like thumbs.db</param>
/// <param name="skipByModifiedDate">Does not copy if the destiny file has the same or more recent modified date</param>
public static string FileCopyStream(string sourcePath, string destPath, bool skipHiddenFiles = true, bool skipByModifiedDate = true)
{
// Buffer should be 64K = 65536 bytes
// Increasing the buffer size beyond 64k will not help in any circunstance,
// as the underlying SMB protocol does not support buffer lengths beyond 64k."
byte[] buffer = new byte[65536];
if (!File.Exists(sourcePath))
return $"is not a file: '{sourcePath}'";
FileInfo sourcefileInfo = new FileInfo(sourcePath);
FileInfo destFileInfo = null;
if (File.Exists(destPath))
destFileInfo = new FileInfo(destPath);
if (skipHiddenFiles)
{
if (sourcefileInfo.Attributes.HasFlag(FileAttributes.Hidden))
return $"Hidden File Not Copied: '{sourcePath}'";
}
using (FileStream input = sourcefileInfo.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (FileStream output = new FileStream(destPath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite, buffer.Length))
{
if (skipByModifiedDate && destFileInfo != null)
{
if (destFileInfo.LastWriteTime < sourcefileInfo.LastWriteTime)
{
input.CopyTo(output, buffer.Length);
destFileInfo.LastWriteTime = sourcefileInfo.LastWriteTime;
return $"Replaced: '{sourcePath}'";
}
else
{
return $"NOT replaced (more recent or same file): '{sourcePath}'";
}
}
else
{
input.CopyTo(output, buffer.Length);
destFileInfo = new FileInfo(destPath);
destFileInfo.LastWriteTime = sourcefileInfo.LastWriteTime;
return $"New File: '{sourcePath}'";
}
}
}
public static class Extensions
{
public static void Copy(this DirectoryInfo self, DirectoryInfo destination, bool recursively)
{
foreach (var file in self.GetFiles())
{
file.CopyTo(Path.Combine(destination.FullName, file.Name));
}
if (recursively)
{
foreach (var directory in self.GetDirectories())
{
directory.Copy(destination.CreateSubdirectory(directory.Name), recursively);
}
}
}
}
使用示例:
var sourceDirectory = new DirectoryInfo(@"C:\source");
var destinationDirectory = new DirectoryInfo(@"C:\destination");
if (destinationDirectory.Exists == false)
{
sourceDirectory.Copy(destinationDirectory, recursively: true);
}