Bir dizinin tüm içeriğini C # içine kopyalayın


524

Bir dizinin tüm içeriğini bir konumdan diğerine C # 'da kopyalamak istiyorum.

System.IOÇok fazla özyineleme olmadan sınıfları kullanarak bunu yapmanın bir yolu yoktur .

VB'de aşağıdakilere referans eklersek kullanabileceğimiz bir yöntem vardır Microsoft.VisualBasic:

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

Bu oldukça çirkin bir kesmek gibi görünüyor. Daha iyi bir yol var mı?


101
Aşağıda yayınlanan alternatiflere bakıldığında, VB yolunun çok çirkin görünmediğini söyleyebilirim.
Kevin Kershaw

41
.NET Framework'ün bir parçası olduğunda nasıl bir saldırı olabilir? Kod yazmayı bırak ve sahip olduklarını kullan.
AMissico

15
Bu yaygın bir yanlış anlamadır. Microsft.VisualBasic, VB'de kodlamayı çok daha kolay hale getiren tüm yaygın Visual Basic prosedürlerini içerir. Microsot.VisualBasic.Compatibility, VB6 mirası için kullanılan montajdır.
AMissico

63
Microsoft.VisualBasic.Devices.Computer.FileSystem için 2.000'den fazla kod satırı vardır. CopyDirectory, bir üst klasörü bir alt klasöre ve diğer denetimlere kopyalamamanızı sağlar. Oldukça optimize edilmiştir, vb. Seçilen cevap en iyi ihtimalle kırılgan koddur.
AMissico

17
@AMissico - tamam, neden bu optimize edilmiş ve tam kod içeri giriyor Microsoft.VisualBasicve girmiyor System.IO? Mono'da olmamasının nedeni, 'çekirdek' olarak kabul edilen tüm kütüphanelerin System.[something]- diğerlerinin hepsi olmadığıdır. Ek bir DLL başvurusunda sorunum yok, ancak Microsoft'un bu özelliği içermemesinin iyi bir nedeni var System.IO.
Keith

Yanıtlar:


553

Daha kolay

//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);

25
Gerçekten güzel bir kod parçası ama bu herhangi bir yerde kullanılabilecek bir kod türü değil. Geliştiriciler dikkatli olmalı çünkü dirPath.Replace istenmeyen sonuçlara neden olabilir. Sadece net üzerinden kopyala yapıştır gibi insanlar için bir uyarı. @Jaysponsored tarafından gönderilen kod, string.Replace kullanmadığı için daha güvenlidir ancak eminim ki köşe vakaları da vardır.
Alex

17
Hedef dizin zaten varsa bir istisna atacağından bu koda dikkat edin. Ayrıca, varolan dosyaların üzerine yazılmaz. Her dizini oluşturmadan önce bir kontrol ekleyin ve varsa hedef dosyanın üzerine yazmak için File.Copy'nin aşırı yüklenmesini kullanın.
joerage

30
@Xaisoft - Replaceörneği için sen, yolun içine bir yinelenen desen varsa bir sorunu var "sourceDir/things/sourceDir/things"olması gerektiğini "destinationDir/things/sourceDir/things", ancak bunu değiştirmek kullanırsanız olur"destinationDir/things/destinationDir/things"
Keith

35
Neden *.*yerine *? Uzantıları olmayan dosyaları da kopyalamak istemiyor musunuz?
Daryl

10
Bir şeyler oluşturalım ve Açık Kaynak .NET Çekirdeğine katkıda
bulunalım

231

Hmm, sanırım soruyu yanlış anlıyorum ama riske atacağım. Aşağıdaki basit yöntemde sorun nedir?

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));
}

DÜZENLEME Bu gönderi, aynı derecede basit bir soruya bu kadar basit bir cevap için etkileyici sayıda aşağı oy aldığından, bir açıklama eklememe izin verin. Lütfen indirmeden önce bunu okuyun .

Her şeyden önce, bu kod söz konusu kodun yerine bir değiştirme olarak tasarlanmamıştır. Sadece örnekleme amaçlıdır.

Microsoft.VisualBasic.Devices.Computer.FileSystem.CopyDirectorybu yanıtta bulunmayan bazı ek doğruluk testleri (örneğin, kaynak ve hedefin geçerli dizin olup olmadığı, kaynağın hedefin bir üst öğesi olup olmadığı vb.) yapar. Bu kod muhtemelen daha da optimize edilmiştir.

Bununla birlikte, kod iyi çalışıyor . O etmiştir (hemen hemen aynı) yıl süreyle olgun bir yazılım kullanılmıştır. Tüm IO işlemcilerinde bulunan doğal yapışkanlığın dışında (örneğin, kodunuz yazarken kullanıcı USB sürücüsünü manuel olarak çıkarırsa ne olur?), Bilinen bir sorun yoktur.

Özellikle, burada özyineleme kullanımının kesinlikle bir sorun olmadığını belirtmek isterim. Ne teoride (kavramsal olarak, en zarif çözüm) ne de pratikte: bu kod yığının üzerine taşmaz . Yığın, derin yuvalanmış dosya hiyerarşilerini bile işleyebilecek kadar büyüktür. Yığın alanı sorun haline gelmeden çok önce, klasör yolu uzunluğu sınırlaması devreye girer.

Kötü niyetli bir kullanıcının , her biri bir harflik derin iç içe dizinler kullanarak bu varsayımı kırabileceğine dikkat edin . Bunu denemedim. Ancak sadece konuyu açıklamak için: Bu kodun tipik bir bilgisayarda taşmasını sağlamak için dizinlerin birkaç bin kez iç içe yerleştirilmesi gerekir . Bu sadece gerçekçi bir senaryo değil.


5
Bu kafa özyineleme. Dizinler yeterince derin yuvalanmışsa yığın taşmasına avlanabilir.
spoulson

19
Çok yakın zamana kadar, dizin yuvalama derinliği işletim sistemi tarafından kısıtlandı. Birkaç yüz kereden fazla iç içe dizinler (hatta) bulacaksınız şüpheliyim. Yukarıdaki kod çok daha fazla zaman alabilir .
Konrad Rudolph

5
Özyinelemeli yaklaşımı seviyorum, yığın taşması riski en kötü ihtimalle minimumdur.
David Basarab

49
@DTashkinov: afedersiniz ama bu biraz aşırı görünüyor. Neden açık kod == downvote? Tersi doğru olmalıdır. Yerleşik yöntem zaten gönderilmişti, ancak Keith özellikle başka bir yöntem istedi . Ayrıca, son cümlenizle ne demek istediniz? Maalesef, aşağı oylama nedenlerinizi hiç anlamıyorum.
Konrad Rudolph

6
@ AMissico: ne daha iyi ? Kimse çerçeveden VB kodundan daha iyi olduğunu iddia etmedi. Biz biliyoruz öyle değil.
Konrad Rudolph

132

MSDN'den kopyalandı :

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.
}

8
Dizinin var olup olmadığını kontrol etmek için bir neden yoktur, sadece dizin varsa hiçbir şey yapmaz Directoty.CreateDirectory arayın.
Tal Jerome

1
256 karakterden uzun yollarla uğraşmak isteyenler için ZetaLongPaths adlı bir Nuget paketi kullanabilirsiniz
AK

2
Bu cevap hepsinden daha faydalı gibi görünüyor. Dizeler yerine DirectoryInfo kullanılarak bir çok potansiyel sorun önlenir.
DaedalusAlpha

50

Bunu dene:

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 argümanlarınız değişebilir, ancak fikri anlarsınız.


3
/ E tüm alt dizinleri (boş olanları bile) kopyalamasını söyler. / Hedef yoksa, bu ada sahip bir dizin oluşturduğunu söylerim.
d4nt

6
güvenli olmak için çift tırnak ekleyin.
jaysonragasa

6
Varolan dosyaların üzerine yazılmasını istemenizi önlemek için / Y ekleyin. stackoverflow.com/q/191209/138938
Jon Crowell

16
Üzgünüm, ama bu korkunç. Hedef sistemin pencereler olduğunu varsayar. Gelecekteki sürümlerin bu belirli yolda xcopy.exe içerdiğini varsayar. Xcopy parametrelerinin değişmediğini varsayar. Xcopy parametrelerini dize olarak bir araya getirmeyi gerektirir, bu da çok sayıda hata potansiyeli sunar. Ayrıca örnek, diğer yöntemlerin aksine bu sessizce başarısız olacağı için beklediğim, başlatılan işlemin sonuçları için herhangi bir hata işleme bahsetmez.
cel sharp

3
@MatthiasJansen, bence çok kişisel aldın. Cevap noktaya ve bunun nasıl elde edileceği hakkında çok şey açıklıyor ... Soru çapraz platform uyumluluğunu talep etmediğinden veya xcopy veya başka bir şey kullanmadan talep etmediği için poster bunun nasıl bir şekilde başarılabileceğini açıklamak için cevapladı ... aynı şeyi yapmanın 1000 yolu olabilir ve cevaplar değişebilir. Yorumunu oyluyorum.
KMX

47

Veya zor yoldan gitmek istiyorsanız, Microsoft.VisualBasic projenize bir başvuru ekleyin ve ardından aşağıdakileri kullanın:

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

Ancak, VB dll yüklemek zorunda kalmayacağı için özyinelemeli işlevlerden birini kullanmak daha iyi bir yoldur.


1
Bu zaten nasıl yaptığımdan çok farklı değil - hala yapabilmek için VB'nin geriye dönük uyumluluklarını yüklemeniz gerekiyor.
Keith

10
VB montajını yüklemek pahalı mı? VB seçenekleri C # versiyonlarından çok daha zariftir.
jwmiller5

3
Ne "VB'nin geriye dönük uyumluluk"? CopyDirectory, Kabuk veya Çerçeve kullanır.
AMissico

3
Keşke açık olsaydı System.IO.Directory, ama yeniden yazmaktan daha iyi!
Josh M.

2
Bu imo, diğer seçeneklerden daha kolay gitmek için bir yoldur
reggaeguitar

38

Bu site bana her zaman çok yardımcı oldu ve şimdi başkalarına bildiklerimle yardım etme sırası bende.

Umarım aşağıdaki kodum birisi için yararlıdır.

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 + 1)));
        // 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 + 1)));
    }

1
Sondaki ters eğik çizgiyi hatırlayın
Alexey F

24
Millet, kullanın Path.Combine(). Dosya yollarını bir araya getirmek için asla dize birleştirme kullanmayın.
Andy

3
Yukarıdaki kod snippet'inde bir OBOB var. Kullanmalısın source_dir.Length + 1, değil source_dir.Length.
PellucidWombat

Bu kod iyi bir kavram, ama ... Bir dosyanın "." içinde, bu yüzden ystem.IO.Directory.GetFiles (source_dir, "*", System.IO.SearchOption.AllDirectories)) kullanmanız daha iyi olur
Jean Libera

Teşekkürler @JeanLibera, haklısın. Kodu önerinizle değiştirdim.
jaysponsored

14

Yığın taşmasını önlemek için klasörü özyinelemesiz özyinelemeli olarak kopyalayın.

public static void CopyDirectory(string source, string target)
{
    var stack = new Stack<Folders>();
    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;
    }
}

yararlı özyineleme olmayan şablon :)
Minh Nguyen

2
Yol sınırını
Ed S.

5

İşte böyle IO görevleri için kullandığım bir yardımcı sınıf.

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<stringArray.Length ; i++)
                multiString += stringArray[i] + '\0';

            multiString += '\0';

            return multiString;
        }

        public static bool Copy(string source, string dest)
        {
            return Copy(new String[] { source }, new String[] { dest });
        }

        public static bool Copy(String[] source, String[] dest)
        {
            Win32.SHFILEOPSTRUCT FileOpStruct = new Win32.SHFILEOPSTRUCT();

            FileOpStruct.hwnd = IntPtr.Zero;
            FileOpStruct.wFunc = (uint)Win32.FO_COPY;

            String multiSource = StringArrayToMultiString(source);
            String multiDest = StringArrayToMultiString(dest);
            FileOpStruct.pFrom = Marshal.StringToHGlobalUni(multiSource);
            FileOpStruct.pTo = Marshal.StringToHGlobalUni(multiDest);

            FileOpStruct.fFlags = (ushort)Win32.ShellFileOperationFlags.FOF_NOCONFIRMATION;
            FileOpStruct.lpszProgressTitle = "";
            FileOpStruct.fAnyOperationsAborted = 0;
            FileOpStruct.hNameMappings = IntPtr.Zero;

            int retval = Win32.SHFileOperation(ref FileOpStruct);

            if(retval != 0) return false;
            return true;
        }

        public static bool Move(string source, string dest)
        {
            return Move(new String[] { source }, new String[] { dest });
        }

        public static bool Delete(string file)
        {
            Win32.SHFILEOPSTRUCT FileOpStruct = new Win32.SHFILEOPSTRUCT();

            FileOpStruct.hwnd = IntPtr.Zero;
            FileOpStruct.wFunc = (uint)Win32.FO_DELETE;

            String multiSource = StringArrayToMultiString(new string[] { file });
            FileOpStruct.pFrom = Marshal.StringToHGlobalUni(multiSource);
            FileOpStruct.pTo =  IntPtr.Zero;

            FileOpStruct.fFlags = (ushort)Win32.ShellFileOperationFlags.FOF_SILENT | (ushort)Win32.ShellFileOperationFlags.FOF_NOCONFIRMATION | (ushort)Win32.ShellFileOperationFlags.FOF_NOERRORUI | (ushort)Win32.ShellFileOperationFlags.FOF_NOCONFIRMMKDIR;
            FileOpStruct.lpszProgressTitle = "";
            FileOpStruct.fAnyOperationsAborted = 0;
            FileOpStruct.hNameMappings = IntPtr.Zero;

            int retval = Win32.SHFileOperation(ref FileOpStruct);

            if(retval != 0) return false;
            return true;
        }

        public static bool Move(String[] source, String[] dest)
        {
            Win32.SHFILEOPSTRUCT FileOpStruct = new Win32.SHFILEOPSTRUCT();

            FileOpStruct.hwnd = IntPtr.Zero;
            FileOpStruct.wFunc = (uint)Win32.FO_MOVE;

            String multiSource = StringArrayToMultiString(source);
            String multiDest = StringArrayToMultiString(dest);
            FileOpStruct.pFrom = Marshal.StringToHGlobalUni(multiSource);
            FileOpStruct.pTo = Marshal.StringToHGlobalUni(multiDest);

            FileOpStruct.fFlags = (ushort)Win32.ShellFileOperationFlags.FOF_NOCONFIRMATION;
            FileOpStruct.lpszProgressTitle = "";
            FileOpStruct.fAnyOperationsAborted = 0;
            FileOpStruct.hNameMappings = IntPtr.Zero;

            int retval = Win32.SHFileOperation(ref FileOpStruct);

            if(retval != 0) return false;
            return true;
        }
    }
}

Microsoft SHFileOperation'ı Microsoft.VisualBasic için dahili olarak kullandığını unutmayın.
jrh

3

Performansa duyarlı olmayabilir, ancak 30MB klasörleri için kullanıyorum ve kusursuz çalışıyor. Ayrıca, böylesine kolay bir görev için gerekli olan tüm kod ve özyineleme miktarını beğenmedim.

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);

Not: ZipFile, .NET 4.5+ sürümünde System.IO.Compression ad alanında kullanılabilir


1
Ben de öyle sormuyorum, fakat seçilen cevabın özyinelemeye ihtiyacı yok. Bu yanıt diskte bir zip dosyası oluşturur, bu da bir dosya kopyası için çok fazla iştir - sadece verilerin ek bir kopyasını oluşturmakla kalmaz, aynı zamanda işlemci zamanını sıkıştırıp sıkıştırmasını da harcarsınız. Eminim işe yarıyor, muhtemelen ayakkabınıza bir çivi çakabilirsiniz, ancak daha iyi yapmanın daha iyi yolları varken, yanlış gidebilecek daha fazla şeyle daha fazla çalışır.
Keith

Ben bununla sonuçlanan nedeni dize değiştirmeleridir. Diğerlerinin de belirttiği gibi, kabul edilen cevap birçok endişe uyandırır; bağlantı bağlantısı çalışmayabilir, ayrıca klasör desenini veya uzantı veya adı olmayan dosyaları yineleyebilir. Daha az kod, yanlış gitme şansı daha az. Ve işlemci süresi benim için bir endişe olmadığından, özel durumum için uygun hale getiriyor
AlexanderD

2
Evet, bu, tek bir trafik ışığından kaçınmak için 1000 mil yoldan çıkmak gibi, ama bu sizin yolculuğunuz, bu yüzden devam edin. Klasör desenlerini kontrol etmek, ZIP'in başlık altında yapması gerekenlerle karşılaştırıldığında önemsizdir. İşlemciyi, diski, elektriği boşa harcamamayı veya bunun aynı makinedeki diğer programlarla birlikte çalışması gerekenleri önemseyen herkes için buna şiddetle tavsiye ediyorum. Ayrıca, röportajda bu tür bir soru asla "kodum basit, bu yüzden işlemci zaman umurumda değil" ile gitmek sorulursa - iş almazsınız.
Keith

1
@ Justin-r tarafından verilen cevaba geçtim . Yine de, bu cevabı orada yapmanın başka bir yolu olarak bırakacağım
AlexanderD

1
Klasörler ayrı ağ paylaşımlarındaysa ve çok sayıda dosya içeriyorsa, bu bence en iyi seçenek olacaktır.
Danny Parker

2

Muhtemelen hataları kontrol etmek istediğiniz ve bir sunucu ve geliştirme makinesinde çalışıyorsanız xcopy yollarını değiştirmek zorunda olmadığınız için d4nt'nin cevabında küçük bir gelişme:

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));
    }
}

2

Bu benim kodum umut bu yardım

    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<string> files = GetAllFileAndFolder(source);

            foreach (string file in files)
            {
                KCOPY(file, target);
            }
        }
    }

    private List<string> GetAllFileAndFolder(string path)
    {
        List<string> allFile = new List<string>();
        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;
    }

Seçilen cevabı görün, SearchOptionklasör ve dosya aramalarındaki bayrağı kullanarak bunu 4 satır satırda yapın. Ayrıca .HasFlagartık numaralandırmalarda uzantıya göz atın.
Keith

2

Konrad'ın popüler cevabını beğendiyseniz, ancak çocuklarını sourceklasörün altına targetkoymak yerine altında bir klasör olmasını istiyorsanız target, işte bunun kodu. Yeni oluşturulanı döndürür DirectoryInfo, ki bu kullanışlı:

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;
}

2

Her zaman kullanabilirsiniz Bu Microsoftun web sitesinden alınmıştır.

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);
        }
    }
}

1
Bu harika - satırın file.CopyTo(temppath, false);"bu dosyayı bu yere kopyalayın, yalnızca mevcut değilse" yazdığını unutmayın; çoğu zaman istediğimiz şey değildir. Ancak, bunun neden varsayılan olduğunu anlayabiliyorum. Dosyaların üzerine yazma yöntemine bir bayrak ekleyebilirsiniz.
Andy

2

tboswell'in yerine Prova sürümü (dosya yolunda yinelenen desene dayanıklıdır)

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);
    }

3
Millet, kullanın Path.Combine(). Dosya yollarını bir araya getirmek için asla dize birleştirme kullanmayın.
Andy

2

Benim çözümüm temelde @ Termininja'nın cevabının bir modifikasyonudur, ancak biraz geliştirdim ve kabul edilen cevaptan 5 kat daha hızlı görünüyor.

public static void CopyEntireDirectory(string path, string newPath)
{
    Parallel.ForEach(Directory.GetFileSystemEntries(path, "*", SearchOption.AllDirectories)
    ,(fileName) =>
    {
        string output = Regex.Replace(fileName, "^" + Regex.Escape(path), newPath);
        if (File.Exists(fileName))
        {
            Directory.CreateDirectory(Path.GetDirectoryName(output));
            File.Copy(fileName, output, true);
        }
        else
            Directory.CreateDirectory(output);
    });
}

DÜZENLEME: @Ahmed Sabry'ı tam paralel foreach olarak değiştirmek daha iyi sonuç verir, ancak kod özyinelemeli işlev kullanır ve bazı durumlarda ideal değildir.

public static void CopyEntireDirectory(DirectoryInfo source, DirectoryInfo target, bool overwiteFiles = true)
{
    if (!source.Exists) return;
    if (!target.Exists) target.Create();

    Parallel.ForEach(source.GetDirectories(), (sourceChildDirectory) =>
        CopyEntireDirectory(sourceChildDirectory, new DirectoryInfo(Path.Combine(target.FullName, sourceChildDirectory.Name))));

    Parallel.ForEach(source.GetFiles(), sourceFile =>
        sourceFile.CopyTo(Path.Combine(target.FullName, sourceFile.Name), overwiteFiles));
}

1

Önceki kod için özür dilerim, hala hatalar vardı :( (en hızlı silah sorununun avına düştü). İşte test edilmiş ve çalışıyor.

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);
    }
}

1

İşte DirectoryInfo a la FileInfo.CopyTo için bir uzantı yöntemi ( overwriteparametreye dikkat edin ):

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;
}

1

Bu sınıfı kullanın.

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);
    }
}

1
Bu, .ToList().ForEach((sadece doğrudan dizinleri numaralandırmaktan biraz daha fazla çalışma, bellek ve biraz daha yavaş olan) ve bir genişletme yöntemi olarak yeniden düzenlenmiş diğer cevaplara benzer . Seçilen cevap SearchOption.AllDirectoriesyinelemeyi kullanır ve önler, bu yüzden bu modele geçmenizi tavsiye ederim. Ayrıca, genellikle uzatma yöntemlerinde türün adına ihtiyacınız yoktur - Bunu yeniden adlandırırdım, CopyTo()böylece olursourceDir.CopyTo(destination);
Keith

1

Tüm klasörlerin ve dosyaların kopyalanması için yalnızca bir döngüye sahip bir varyant:

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);
}

Kullanacaksanız Regex, muhtemelen Regex.Escape(path)ifade kompozisyonunuzun bir parçası olarak da (özellikle Windows yol ayırıcısını göz önünde bulundurarak) kullanmalısınız. Sen belki de oluşturarak (ve belki derleme) bir fayda elde new Regex()döngünün nesne dışında ziyade statik yöntemine dayanarak.
jimbobmcgee

0

Herhangi bir kod daha iyi (özyineleme ile DirectoryInfo uzantısı yöntemi)

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;
        }
    }

1
Hata ayıklamayı zorlaştırmak için özyineleme (bunun gerekmediği) kullanmak ve istisnaları gizlemek dışında bunun kabul edilen yanıta ne eklediğinden emin değilim.
Keith

0

Klasörün tüm dosyalarını kopyalayın ve değiştirin

        public static void CopyAndReplaceAll(string SourcePath, string DestinationPath, string backupPath)
    {
            foreach (string dirPath in Directory.GetDirectories(SourcePath, "*", SearchOption.AllDirectories))
            {
                Directory.CreateDirectory($"{DestinationPath}{dirPath.Remove(0, SourcePath.Length)}");
                Directory.CreateDirectory($"{backupPath}{dirPath.Remove(0, SourcePath.Length)}");
            }
            foreach (string newPath in Directory.GetFiles(SourcePath, "*.*", SearchOption.AllDirectories))
            {
                if (!File.Exists($"{ DestinationPath}{newPath.Remove(0, SourcePath.Length)}"))
                    File.Copy(newPath, $"{ DestinationPath}{newPath.Remove(0, SourcePath.Length)}");
                else
                    File.Replace(newPath
                        , $"{ DestinationPath}{newPath.Remove(0, SourcePath.Length)}"
                        , $"{ backupPath}{newPath.Remove(0, SourcePath.Length)}", false);
            }
    }

Cevap için şerefe, ama bunun ne eklediğinden emin değilim. Ayrıca try catch throwanlamsız.
Keith

0

Aşağıdaki kod microsoft öneridir nasıl yapılır kopya dizinleri ve sevgili tarafından paylaşılan @iato ama sadece kopya alt dizinleri ve özyinelemeli kaynak klasörün dosya ve bunun kendini klasör kaynak kopyalamaz sağ tıklama gibi (-> kopya ).

ancak bu cevabın altında aldatıcı bir yol var :

private static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs = true)
        {
            // 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);
                }
            }
        }

kopyalamak istediğiniz takdirde içeriğini ait kaynak klasörü ve alt klasörleri yinelemeli sadece bu gibi kullanabilirsiniz:

string source = @"J:\source\";
string dest= @"J:\destination\";
DirectoryCopy(source, dest);

ancak kaynak dizini kendiniz kopyalamak istiyorsanız (kaynak klasöre sağ tıklayıp kopyalayıp tıklattıktan sonra yapıştırdığınız hedef klasöre benzer şekilde) şöyle kullanmalısınız:

 string source = @"J:\source\";
 string dest= @"J:\destination\";
 DirectoryCopy(source, Path.Combine(dest, new DirectoryInfo(source).Name));

Zaten aşağıda bazı cevaplar yayınlanmıştır: stackoverflow.com/a/45199038/1951524
Martin Schneider

Teşekkürler @ MA-Maddin, ancak kaynak klasörün kendisini kopyalıyor mu? ya da sadece içeriği?
Arash.Zandi
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.