Скопируйте все содержимое каталога в C #
Я хочу скопировать все содержимое каталога из одного места в другое в C #.
Кажется, что нет способа сделать это, используя classы System.IO
без большой рекурсии.
В VB существует метод, который мы можем использовать, если добавить ссылку на Microsoft.VisualBasic
:
- jQuery: получить имя файла, выбранное из
- Попытка скопировать файл с одного ПК XP на другой с помощью WMI, поскольку RPC и UNC недоступны
- Как скопировать данные из закрытых книг (их закрытие) в основную книгу с помощью VBA
- Как скопировать объект в Java?
- Как клонировать BufferedImage
new Microsoft.VisualBasic.Devices.Computer(). FileSystem.CopyDirectory( sourceFolder, outputFolder );
Это кажется довольно уродливым взломом. Есть ли способ лучше?
- В MySQL я могу скопировать одну строку для вставки в ту же таблицу?
- Копирование одной структуры в другую
- Могу ли я показать прогресс копирования файла с помощью FileInfo.CopyTo () в .NET?
- Использование FileSystemWatcher для мониторинга каталога
- Скопировать структуру в структуру в C
- data.table join, затем добавьте столбцы в существующий файл data.frame без повторной копии
- VBA для копирования файла из одного каталога в другой
- Почему конструктор копирования принимает свой параметр по ссылке в C ++?
Намного легче
//Now Create all of the directories foreach (string dirPath in Directory.GetDirectories(SourcePath, "*", SearchOption.AllDirectories)) 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)) File.Copy(newPath, newPath.Replace(SourcePath, DestinationPath), true);
Хм, я думаю, что неправильно понимаю вопрос, но я буду рисковать. Что случилось со следующим простым методом?
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)); }
EDIT Поскольку эта публикация собрала внушительное количество downvotes для такого простого ответа на столь же простой вопрос, позвольте мне добавить объяснение. Пожалуйста, прочитайте это, прежде чем начинать .
Прежде всего, этот код не предназначен для замены кода в вопросе. Это только для иллюстрации.
Microsoft.VisualBasic.Devices.Computer.FileSystem.CopyDirectory
выполняет некоторые дополнительные проверки правильности (например, являются ли источники и цель действительными каталогами, является ли источник родителем объекта и т. Д.), Которые отсутствуют в этом ответе. Этот код, вероятно, также более оптимизирован.
Тем не менее, код работает хорошо . Он (почти идентично) использовался в зрелом программном обеспечении в течение многих лет. Помимо неотъемлемой изменчивости, присутствующей во всех манипуляциях ввода-вывода (например, что произойдет, если пользователь вручную отключит 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. }
Попробуй это:
Process proc = new Process(); proc.StartInfo.UseShellExecute = true; proc.StartInfo.FileName = Path.Combine(Environment.SystemDirectory, "xcopy.exe"); proc.StartInfo.Arguments = @"C:\source C:\destination /E /I"; proc.Start();
Ваши аргументы xcopy могут отличаться, но вы получаете эту идею.
Или, если вы хотите идти сложным способом, добавьте ссылку на свой проект для Microsoft.VisualBasic, а затем используйте следующее:
Microsoft.VisualBasic.FileIO.FileSystem.CopyDirectory(fromDirectory, toDirectory);
Однако использование одной из рекурсивных функций – лучший способ, так как ему не придется загружать dll VB.
Этот сайт всегда помогал мне много, и теперь моя очередь помогать другим в том, что я знаю.
Я надеюсь, что мой код ниже будет полезен для кого-то.
string source_dir = @"E:\"; string destination_dir = @"C:\"; // substring is to remove destination_dir absolute path (E:\). // Create subdirectory structure in destination foreach (string dir in System.IO.Directory.GetDirectories(source_dir, "*", System.IO.SearchOption.AllDirectories)) { System.IO.Directory.CreateDirectory(System.IO.Path.Combine(destination_dir, dir.Substring(source_dir.Length))); // Example: // > C:\sources (and not C:\E:\sources) } foreach (string file_name in System.IO.Directory.GetFiles(source_dir, "*", System.IO.SearchOption.AllDirectories)) { System.IO.File.Copy(file_name, System.IO.Path.Combine(destination_dir, file_name.Substring(source_dir.Length))); }
Скопируйте папку рекурсивно без рекурсии, чтобы избежать переполнения стека.
public static void CopyDirectory(string source, string target) { var stack = new Stack(); stack.Push(new Folders(source, target)); while (stack.Count > 0) { var folders = stack.Pop(); Directory.CreateDirectory(folders.Target); foreach (var file in Directory.GetFiles(folders.Source, "*.*")) { File.Copy(file, Path.Combine(folders.Target, Path.GetFileName(file))); } foreach (var folder in Directory.GetDirectories(folders.Source)) { stack.Push(new Folders(folder, Path.Combine(folders.Target, Path.GetFileName(folder)))); } } } public class Folders { public string Source { get; private set; } public string Target { get; private set; } public Folders(string source, string target) { Source = source; Target = target; } }
Вот class утилиты, который я использовал для задач ввода-вывода, подобных этому.
using System; using System.Runtime.InteropServices; namespace MyNameSpace { public class ShellFileOperation { private static String StringArrayToMultiString(String[] stringArray) { String multiString = ""; if (stringArray == null) return ""; for (int i=0 ; i
Небольшое улучшение в ответе d4nt, поскольку вы, вероятно, хотите проверить наличие ошибок и не должны изменять пути xcopy, если работаете на сервере и машине разработки:
public void CopyFolder(string source, string destination) { string xcopyPath = Environment.GetEnvironmentVariable("WINDIR") + @"\System32\xcopy.exe"; ProcessStartInfo info = new ProcessStartInfo(xcopyPath); info.UseShellExecute = false; info.RedirectStandardOutput = true; info.Arguments = string.Format("\"{0}\" \"{1}\" /E /I", source, destination); Process process = Process.Start(info); process.WaitForExit(); string result = process.StandardOutput.ReadToEnd(); if (process.ExitCode != 0) { // Or your own custom exception, or just return false if you prefer. throw new InvalidOperationException(string.Format("Failed to copy {0} to {1}: {2}", source, destination, result)); } }
Если вам нравится популярный ответ Konrad, но вы хотите, чтобы source
был папкой под target
, а не помещал ее под target
папкой, вот код для этого. Он возвращает вновь созданный DirectoryInfo
, который удобен:
public static DirectoryInfo CopyFilesRecursively(DirectoryInfo source, DirectoryInfo target) { var newDirectoryInfo = target.CreateSubdirectory(source.Name); foreach (var fileInfo in source.GetFiles()) fileInfo.CopyTo(Path.Combine(newDirectoryInfo.FullName, fileInfo.Name)); foreach (var childDirectoryInfo in source.GetDirectories()) CopyFilesRecursively(childDirectoryInfo, newDirectoryInfo); return newDirectoryInfo; }
Вы всегда можете использовать это , взятое с веб-сайта Microsoft.
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); } } }
tboswell заменяет версию Proof (которая устойчива к повторению шаблона в пути к файлу)
public static void copyAll(string SourcePath , string DestinationPath ) { //Now Create all of the directories foreach (string dirPath in Directory.GetDirectories(SourcePath, "*", SearchOption.AllDirectories)) Directory.CreateDirectory(Path.Combine(DestinationPath ,dirPath.Remove(0, SourcePath.Length )) ); //Copy all the files & Replaces any files with the same name foreach (string newPath in Directory.GetFiles(SourcePath, "*.*", SearchOption.AllDirectories)) File.Copy(newPath, Path.Combine(DestinationPath , newPath.Remove(0, SourcePath.Length)) , true); }
Возможно, это не относится к производительности, но я использую его для 30 МБ папок, и он работает безупречно. Кроме того, мне не понравился весь объем кода и recursion, необходимые для такой простой задачи.
var source_folder = "c:\src"; var dest_folder = "c:\dest"; var zipFile = source_folder + ".zip"; ZipFile.CreateFromDirectory(source_folder, zipFile); ZipFile.ExtractToDirectory(zipFile, dest_folder); File.Delete(zipFile);
Примечание. ZipFile доступен в .NET 4.5+ в пространстве имен System.IO.Compression
Извините за предыдущий код, у него все еще были ошибки 🙁 (стал жертвой самой быстрой проблемы с пистолетом). Здесь он протестирован и работает. Ключ – это 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); } }
Это мой код, надеюсь, эта помощь
private void KCOPY(string source, string destination) { if (IsFile(source)) { string target = Path.Combine(destination, Path.GetFileName(source)); File.Copy(source, target, true); } else { string fileName = Path.GetFileName(source); string target = System.IO.Path.Combine(destination, fileName); if (!System.IO.Directory.Exists(target)) { System.IO.Directory.CreateDirectory(target); } List files = GetAllFileAndFolder(source); foreach (string file in files) { KCOPY(file, target); } } } private List GetAllFileAndFolder(string path) { List allFile = new List (); foreach (string dir in Directory.GetDirectories(path)) { allFile.Add(dir); } foreach (string file in Directory.GetFiles(path)) { allFile.Add(file); } return allFile; } private bool IsFile(string path) { if ((File.GetAttributes(path) & FileAttributes.Directory) == FileAttributes.Directory) { return false; } return true; }
Ниже приведен метод расширения для DirectoryInfo a la FileInfo.CopyTo (обратите внимание на параметр overwrite
):
public static DirectoryInfo CopyTo(this DirectoryInfo sourceDir, string destinationPath, bool overwrite = false) { var sourcePath = sourceDir.FullName; var destination = new DirectoryInfo(destinationPath); destination.Create(); foreach (var sourceSubDirPath in Directory.EnumerateDirectories(sourcePath, "*", SearchOption.AllDirectories)) Directory.CreateDirectory(sourceSubDirPath.Replace(sourcePath, destinationPath)); foreach (var file in Directory.EnumerateFiles(sourcePath, "*", SearchOption.AllDirectories)) File.Copy(file, file.Replace(sourcePath, destinationPath), overwrite); return destination; }
Лучше, чем любой код (метод расширения для DirectoryInfo с рекурсией)
public static bool CopyTo(this DirectoryInfo source, string destination) { try { foreach (string dirPath in Directory.GetDirectories(source.FullName)) { var newDirPath = dirPath.Replace(source.FullName, destination); Directory.CreateDirectory(newDirPath); new DirectoryInfo(dirPath).CopyTo(newDirPath); } //Copy all the files & Replaces any files with the same name foreach (string filePath in Directory.GetFiles(source.FullName)) { File.Copy(filePath, filePath.Replace(source.FullName,destination), true); } return true; } catch (IOException exp) { return false; } }
Используйте этот class.
public static class Extensions { public static void CopyTo(this DirectoryInfo source, DirectoryInfo target, bool overwiteFiles = true) { if (!source.Exists) return; if (!target.Exists) target.Create(); Parallel.ForEach(source.GetDirectories(), (sourceChildDirectory) => CopyTo(sourceChildDirectory, new DirectoryInfo(Path.Combine(target.FullName, sourceChildDirectory.Name)))); foreach (var sourceFile in source.GetFiles()) sourceFile.CopyTo(Path.Combine(target.FullName, sourceFile.Name), overwiteFiles); } public static void CopyTo(this DirectoryInfo source, string target, bool overwiteFiles = true) { CopyTo(source, new DirectoryInfo(target), overwiteFiles); } }
Один вариант с одним контуром для копирования всех папок и файлов:
foreach (var f in Directory.GetFileSystemEntries(path, "*", SearchOption.AllDirectories)) { var output = Regex.Replace(f, @"^" + path, newPath); if (File.Exists(f)) File.Copy(f, output, true); else Directory.CreateDirectory(output); }