C#如何遍历与目标匹配的源文件夹或子文件夹

时间:2013-07-31 18:08:01

标签: c#

我需要覆盖从源到目标目录的文件。 每个文件夹的结构都不同,所以我试图以通用的方式进行。 问题是,每个文件夹(源和目标)可能有许多子目录或根本没有。

我目前的代码是:

//copy and overwrite the files depending on whatever is in the destination
//search through the destination to find the file
foreach (var dstfile in Directory.GetFiles(targetDir))
{
  //search through the source to find the matching file
  foreach (var srcfile  in Directory.GetFiles(sourceDir))
  {
     //cut off the source file from the source path 
     strSrcFile = srcfile.Split(Path.DirectorySeparatorChar).Last();
     strDstFile = dstfile.Split(Path.DirectorySeparatorChar).Last();

    //if the destination and source files match up, replace the desination with the source
    if (strSrcFile == strDstFile)
    {
      File.Copy(srcfile, Path.Combine(targetDir, Path.GetFileName(strSrcFile)), true);
    }
  }
}


//look through the subfolders to see if any files match up 
foreach (var srcFolder in Directory.GetDirectories(sourceDir))
{
   //search through the source for the files 
   foreach (var srcFile in Directory.GetFiles(srcFolder))
   {
      //search through the destination for the files 
      foreach (var dstFile in Directory.GetFiles(targetDir))
      {

正如你所看到的,有许多foreach循环,有没有办法简化这个?

4 个答案:

答案 0 :(得分:1)

我没有对此进行测试,但这应该有效(不是100%效率),至少应该给你一些指示

public void UpdateFiles(string directory, string otherDir)
{
   var dirFiles = Directory.EnumerateFiles(directory, "*", 
                        SearchOption.AllDirectories);
   var otherDirFiles = Directory.EnumerateFiles(otherDir, "*", 
                        SearchOption.AllDirectories);

   foreach (var file in dirFiles)
   {
       string fi = Path.GetFileName(file);
       var newFile = otherDirFiles.Where(x => fi == Path.GetFileName(x));
       foreach(var foundFile in newFile)
          File.Copy(file , foundFile, true);

   }
}

答案 1 :(得分:1)

创建目标目录的哈希(字典),然后遍历源目录并查看文件是否已存在。

Dictionary<string,string> lut1 = new Dictionary<string,string>();

foreach (var dstfile in Directory.GetFiles(targetDir))
{
   strDstFile = dstfile.Split(Path.DirectorySeparatorChar).Last();
   lut1 [strDstFile ] = dstfile;
}

foreach (var srcfile  in Directory.GetFiles(sourceDir))
{
   strSrcFile = srcfile.Split(Path.DirectorySeparatorChar).Last();
   string dstfile;
   if (lut1.TryGetValue(strSrcFile,  out dstfile)) {
       File.Copy( srcfile,dstfile,true);
   }
}       

答案 2 :(得分:1)

我只是在控制台应用程序中这样做了...测试它是为主目标文件夹和子文件夹工作,虽然可能不是最有效的。

请致电:

OperateOnSourceFiles(sourceDir, targetDir);

将检查源中的当前文件,然后递归查看所有源子目录。

private static void OperateOnSourceFiles(string source, string targetDir)
{
    //Processes current source folder files
    foreach (var file in Directory.GetFiles(source))
    {
        OverWrite(targetDir, file);
    }

    //Recursively processes files in source subfolders
    List<string> subfolders = Directory.GetDirectories(source).ToList();
    foreach (var subfolder in subfolders)
    {
        OperateOnSourceFiles(subfolder, targetDir);
    }
}

然后你的覆盖函数看起来像这样:

private static void OverWrite(string target, string sourcefile)
{
    //Grab file name
    var strSrcFile = sourcefile.Split(Path.DirectorySeparatorChar).Last();

    //Search current target directory FILES, and copy only if same file name
    List<string> targetfiles = Directory.GetFiles(target).Select(file=>file.Split(Path.DirectorySeparatorChar).Last()).ToList();
    if (targetfiles.Contains(strSrcFile))
    {
        File.Copy(sourcefile, Path.Combine(target, Path.GetFileName(strSrcFile)), true);
    }

    //Recursively search current target directory SUBFOLDERS if any
    List<string> subfolders = Directory.GetDirectories(target).ToList();
    foreach (var subfolder in subfolders)
    {
        OverWrite(subfolder, sourcefile);
    }
}

随意纠正我:)

注意:我意识到它仍然有很多foreach循环,但至少它们不是嵌套的,并且在调试时使生活更轻松。

答案 3 :(得分:0)

我喜欢这个主意,所以我自己试了一下。结果有点复杂然后我想它会。让我们深入研究,好吗?

基本思想是同步目录,因此我们希望引用DirectoryInfo个实例。

var source = new DirectoryInfo(@"C:\SynchSource");
var target = new DirectoryInfo(@"C:\SynchTarget");

Synchronize(source, target);

Synchronize几乎可以通过以下方式运作:

  • 确保所有文件都相同
  • 确保所有目录都相同
  • 浏览所有子目录并遍历

我的实现如下:

void Synchronize(DirectoryInfo sourceDir, DirectoryInfo targetDir)
{
    SynchronizeFiles(sourceDir, targetDir);
    SynchronizeDirectories(sourceDir, targetDir);
    TraverseDirectories(sourceDir, targetDir);
}

注意.Single() - 我们永远不能假设目录中只有一个人/进程在工作。

SynchronizeFiles做了两件事:

  1. 将当前目录中的所有文件复制/覆盖到目标目录中。
  2. 删除源目录中不存在的冗余文件
  3. void MoveFiles(DirectoryInfo sourceDir, DirectoryInfo targetDir)
    {
        foreach (FileInfo sourceFile in sourceDir.GetFiles())
        {
            string targetFilePath = Path.Combine(targetDir.FullName, sourceFile.Name);
            File.Copy(sourceFile.FullName, targetFilePath);
        }
    }
    
    void RemoveRedundantFiles(DirectoryInfo sourceDir, DirectoryInfo targetDir)
    {
        foreach (var targetFile in targetDir.GetFiles())
        {
            var sourceFilePath = Path.Combine(sourceDir.FullName, targetFile.Name);
            if (!File.Exists(sourceFilePath))
            {
                targetFile.Delete();
            }
        }
    }
    

    我们现在可以假设当前目录中的所有文件都是相同的,不多也不少。为了遍历子目录,我们首先要确保目录结构是相同的。我们以与SynchronizeFiles

    类似的方式执行此操作
    1. 在目标目录(CreateMissingDirectories
    2. 中创建缺少的目录
    3. 删除源目录(RemoveRedundantDirectories
    4. 中不再存在的冗余目录
      void CreateMissingDirectories(DirectoryInfo sourceDir, DirectoryInfo targetDir)
      {
          foreach (DirectoryInfo sourceSubDir in sourceDir.GetDirectories())
          {
              string targetSubDirPath = Path.Combine(targetDir.FullName, sourceSubDir.Name);
              if (!Directory.Exists(targetSubDirPath))
              {
                  Directory.CreateDirectory(targetSubDirPath);
              }
          }
      }
      
      void RemoveRedundantDirectories(DirectoryInfo sourceDir, DirectoryInfo targetDir)
      {
          foreach (DirectoryInfo targetSubDir in targetDir.GetDirectories())
          {
              string sourceSubDirPath = Path.Combine(sourceDir.FullName, targetSubDir.Name);
              if (!Directory.Exists(sourceSubDirPath))
              {
                  targetSubDir.Delete(true);
              }
          }
      }
      

      我们处于当前层次结构中的文件和目录相等的状态。我们现在可以遍历所有子目录并调用Synchronize:

      void TraverseDirectories(DirectoryInfo sourceDir, DirectoryInfo targetDir)
      {
          foreach (DirectoryInfo sourceSubDir in sourceDir.GetDirectories())
          {
              DirectoryInfo targetSubDir = targetDir.GetDirectories(sourceSubDir.Name).Single();
              Synchronize(sourceSubDir, targetSubDir);
          }
      }
      

      我们已经完成了。

      对于巨大的目录层次结构,大量或大型文件甚至是在目录中工作的并发进程,还有很大的改进空间。有很多工作要做,它要快(你可能想要缓存GetFiles / GetDirectories),跳过不必要的File.Copy调用(在假设副本之前获取文件哈希)需要)。

      正如旁注:除了偶尔同步文件之外,根据需求,您可能需要查看FileSystemWatcher,它可以在所选目录中递归检测所有更改。