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

私はコンソールアプリでこのようにしました...おそらく最も効率的ではありませんが、メインのターゲットフォルダーとサブフォルダーで動作することをテストしました。

これを呼び出します:

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 に答える
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 に答える
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()- ディレクトリ内で作業している人物/プロセスが 1 つだけであるとは決して想定できません。

SynchronizeFiles次の 2 つのことを行います。

  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 に答える