-1

I would like to compare two equal directories A and B with subdirectories. If I change, delete, or include directories or files in A, I need to reflect on B. Is there is any C # routine that does this? I have this routine but I can't move on. I would like to update only what I changed in A to B and not all. If I delete a directory in A it does not delete in B

  • // Take a snapshot of the file system. IEnumerable list1 = dir1.GetFiles("*.*", System.IO.SearchOption.AllDirectories); IEnumerable list2 = dir2.GetFiles("*.*", System.IO.SearchOption.AllDirectories); – Joelias Andrade Sep 14 '19 at 04:30
  • // Copy each subdirectory using recursion. foreach (DirectoryInfo diSourceSubDir in source.GetDirectories()) { DirectoryInfo nextTargetSubDir = target.CreateSubdirectory(diSourceSubDir.Name); CopyAll(diSourceSubDir, nextTargetSubDir); } – Joelias Andrade Sep 14 '19 at 04:31
  • I need only example to update directory b – Joelias Andrade Sep 14 '19 at 04:35
  • 1
    If you want to add to your question simply [edit](https://stackoverflow.com/posts/57932445/edit) it –  Sep 14 '19 at 04:53
  • i am not able to develop the code between two directories that works as: in Directory A I Delete or rename files and directories and after must be reflect in B Directory this change.How Can I build this join between them. I tested your code but i not able to go on – Joelias Andrade Sep 15 '19 at 13:06

1 Answers1

1

Once you have the full list of files in each directory, you can use the FullOuterJoin code documented on the page LINQ - Full Outer Join. If you make the key for each be the relative path under DirA and DirB plus other charact, then you'll get a good compare. That will result in three data sets - files in A but not B, files in B but not A, and files that match. Then you can iterate thru each and perform the needed file operations as appropriate. It would look something like this:

public static IEnumerable<TResult> FullOuterJoin<TA, TB, TKey, TResult>(
    this IEnumerable<TA> a,
    IEnumerable<TB> b,
    Func<TA, TKey> selectKeyA,
    Func<TB, TKey> selectKeyB,
    Func<TA, TB, TKey, TResult> projection,
    TA defaultA = default(TA),
    TB defaultB = default(TB),
    IEqualityComparer<TKey> cmp = null)
{
    cmp = cmp ?? EqualityComparer<TKey>.Default;
    var alookup = a.ToLookup(selectKeyA, cmp);
    var blookup = b.ToLookup(selectKeyB, cmp);

    var keys = new HashSet<TKey>(alookup.Select(p => p.Key), cmp);
    keys.UnionWith(blookup.Select(p => p.Key));
    var join = from key in keys
               from xa in alookup[key].DefaultIfEmpty(defaultA)
               from xb in blookup[key].DefaultIfEmpty(defaultB)
               select projection(xa, xb, key);

    return join;
}

IEnumerable<System.IO.FileInfo> filesA = dirA.GetFiles(".", System.IO.SearchOption.AllDirectories); 
IEnumerable<System.IO.FileInfo> filesB = dirB.GetFiles(".", System.IO.SearchOption.AllDirectories); 
var files = filesA.FullOuterJoin(
    filesB,
    f => $"{f.FullName.Replace(dirA.FullName, string.Empty)}",
    f => $"{f.FullName.Replace(dirB.FullName, string.Empty)}",
    (fa, fb, n) => new {fa, fb, n}
);
var filesOnlyInA = files.Where(p => p.fb == null);
var filesOnlyInB = files.Where(p => p.fa == null);

// Define IsMatch - the filenames already match, but consider other things too
// In this example, I compare the filesizes, but you can define any comparison
Func<FileInfo, FileInfo, bool> IsMatch = (a,b) => a.Length == b.Length;
var matchingFiles = files.Where(p => p.fa != null && p.fb != null && IsMatch(p.fa, p.fb));
var diffFiles = files.Where(p => p.fa != null && p.fb != null && !IsMatch(p.fa, p.fb));
//   Iterate and copy/delete as appropriate
Michael Bray
  • 14,998
  • 7
  • 42
  • 68
  • Thanks Michael Bray but as wrote above :i am not able to develop the code between two directories that works as: in Directory A I Delete or rename files and directories and after must be reflect in B Directory this change.How Can I build this join between them. I tested your code but i not able to go on – Joelias Andrade Sep 15 '19 at 13:07