1

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

我目前拥有的代码是这样的:

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

4 回答 4

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

   }
}
于 2013-07-31T18:36:58.317 回答
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);
   }
}       
于 2013-07-31T18:38:55.157 回答
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 循环,但至少它们没有嵌套,并且在调试时让生活更轻松。

于 2013-07-31T18:47:28.933 回答
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. 删除源目录中不再存在的冗余文件
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. 删除源目录中不再存在的冗余目录 ( RemoveRedundantDirectories)
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,它可以递归地检测所选目录中的所有更改。

于 2013-07-31T20:06:58.167 回答