public FileComparisonResult(FileInfoForComparison fileLeft, FileInfoForComparison fileRight, FileComparisonResultType type) { FileInfoLeft = fileLeft; FileInfoRight = fileRight; Type = type; string showPath; if (type == FileComparisonResultType.Same_Contents && FileInfoLeft.Filename != FileInfoRight.Filename) { showPath = StripInitialSlash(FileInfoLeft.Filename) + "; " + StripInitialSlash(FileInfoRight.Filename); } else { showPath = StripInitialSlash(FileInfoLeft?.Filename ?? FileInfoRight.Filename); } ImageIndex = (int)type; SubItems.Add(type.ToString().Replace("_", " ")); SubItems.Add(showPath); if (type == FileComparisonResultType.Changed && fileRight.LastModifiedTime > fileLeft.LastModifiedTime) { // show a red icon if the file on the right is newer. ImageIndex = 5; } }
public static List <FileComparisonResult> Go(SortFilesSettings settings) { var filesInLeft = new DirectoryInfo(settings.LeftDirectory).EnumerateFiles( "*", SearchOption.AllDirectories); var filesInRight = new DirectoryInfo(settings.RightDirectory).EnumerateFiles( "*", SearchOption.AllDirectories); // first, just make an index that simply maps filesizes to filenames. // we don't need to compute any content-hashes yet, because if there // is only one file with that filesize, we know it's not a duplicate. var results = new List <FileComparisonResult>(); var indexLeft = MapFilesizesToFilenames(settings.LeftDirectory, filesInLeft); // go through files on the right foreach (var infoRight in filesInRight) { var filenameRight = infoRight.FullName.Substring( settings.RightDirectory.Length); var objLeft = FindInMap(indexLeft, settings.LeftDirectory, infoRight.FullName, infoRight.Length, settings.SearchDuplicatesCanUseFiletimes, infoRight.LastWriteTimeUtc, filenameRight); if (objLeft != null) { // these are duplicates, they have the same hash and filesize. var objRight = new FileInfoForComparison(filenameRight, infoRight.Length, infoRight.LastWriteTimeUtc, objLeft.ContentHash); results.Add(new FileComparisonResult( objLeft, objRight, FileComparisonResultType.Same_Contents)); } } return(results); }
public static List <FileComparisonResult> Go(SortFilesSettings settings) { var results = new List <FileComparisonResult>(); var filesInLeft = new Dictionary <string, FileInfoForComparison>( StringComparer.OrdinalIgnoreCase); // go through files in left var diLeft = new DirectoryInfo(settings.LeftDirectory); foreach (var info in diLeft.EnumerateFiles("*", SearchOption.AllDirectories)) { var filename = info.FullName.Substring(settings.LeftDirectory.Length); filesInLeft[filename] = new FileInfoForComparison( filename, info.Length, info.LastWriteTimeUtc); } // go through files in right var diRight = new DirectoryInfo(settings.RightDirectory); foreach (var info in diRight.EnumerateFiles("*", SearchOption.AllDirectories)) { var filenameRight = info.FullName.Substring(settings.RightDirectory.Length); if (filesInLeft.TryGetValue(filenameRight, out FileInfoForComparison objLeft)) { objLeft.MarkWhenVisited = true; if (objLeft.FileSize != info.Length || !AreTimesEqual(objLeft.LastModifiedTime, info.LastWriteTimeUtc, settings)) { // looks like a modified file. same path but different filesize/lmt. var filename = info.FullName.Substring(settings.RightDirectory.Length); var objRight = new FileInfoForComparison( filename, info.Length, info.LastWriteTimeUtc); results.Add(new FileComparisonResult( objLeft, objRight, FileComparisonResultType.Changed)); } } else { // looks like a new file var objRight = new FileInfoForComparison( filenameRight, info.Length, info.LastWriteTimeUtc); results.Add(new FileComparisonResult( null, objRight, FileComparisonResultType.Right_Only)); } } // which files did we see in left but not in right? foreach (var kvp in filesInLeft) { if (!kvp.Value.MarkWhenVisited) { // looks like a deleted file since it didn't show up on the right. results.Add(new FileComparisonResult( kvp.Value, null, FileComparisonResultType.Left_Only)); } } return(results); }
public static Dictionary <long, List <FileInfoForComparison> > MapFilesizesToFilenames( string dirName, IEnumerable <FileInfo> files) { // map filesize to List<FileInfoForComparison> or HashSet<FileInfoForComparison>? // chose List<>; maintaining inserted order makes results that look nicer to the user. var map = new Dictionary <long, List <FileInfoForComparison> >(); foreach (var info in files) { var filename = info.FullName.Substring(dirName.Length); var obj = new FileInfoForComparison( filename, info.Length, info.LastWriteTimeUtc); if (!map.TryGetValue(obj.FileSize, out List <FileInfoForComparison> list)) { list = map[obj.FileSize] = new List <FileInfoForComparison>(); } list.Add(obj); } return(map); }
static FileInfoForComparison FindInMap(Dictionary <long, List <FileInfoForComparison> > map, string baseDir, string fullnameToFind, long lengthOfFileToFind, bool useLmtShortcut, DateTime lmt, string partialFilename) { if (lengthOfFileToFind == 0) { // 0-length files compare unequal; often placeholders intentionally created by user return(null); } if (map.TryGetValue(lengthOfFileToFind, out List <FileInfoForComparison> list)) { // look for an entry with the same filename FileInfoForComparison hasSameName = null; foreach (var obj in list) { if (obj.Filename == partialFilename) { hasSameName = obj; break; } } // if enabled, treat files with the same filesize, lmt, and name as equal if (useLmtShortcut && hasSameName != null && hasSameName.LastModifiedTime == lmt) { return(hasSameName); } // change order so that an entry with the same name is checked first. why? // 1) results look nicer when paired this way // 2) same order of results whether or not useLmtShortcut is on // (as long as lmt times are accurate). Consider the case with two duplicates, // one with the same name, and one that sorts earlier. // We prefer to pick the file with the same name to show as the duplicate. if (hasSameName != null) { list = new List <FileInfoForComparison>(list); list.Insert(0, hasSameName); } // we found another file(s) with the same filesize, so // let's compare hashes of the content to see if they're the same. var hash = Utils.GetSha512(fullnameToFind); foreach (var obj in list) { // compute the hash if it hasn't been computed already, then cache it if (obj.ContentHash == null) { obj.ContentHash = Utils.GetSha512( baseDir + obj.Filename); } if (obj.ContentHash == hash) { return(obj); } } } return(null); }