using System.Security.Cryptography; namespace RedundancyFinder { public class Finder { List tasks = new List(); Dictionary redundancies = new Dictionary(); public Dictionary Redundancies { get => redundancies; } string[] extensions; public void FindRedundancies(string[] paths, string[] extensions) { this.extensions = extensions; foreach (var path in paths) { if (Directory.Exists(path)) { ProcessDirectory(path); } else if (File.Exists(path)) { ProcessFile(path); } } // Wait for all tasks to complete Task.WaitAll(tasks.ToArray()); foreach (var redundancy in redundancies.Values.ToList()) { if (redundancy.Paths.Count == 1) { redundancies.Remove(redundancy.Hash); } } } private void ProcessDirectory(string directoryPath) { try { // Process files in the current directory foreach (var file in Directory.GetFiles(directoryPath)) { ProcessFile(file); } // Recursively process subdirectories foreach (var subDirectory in Directory.GetDirectories(directoryPath)) { try { ProcessDirectory(subDirectory); } catch (UnauthorizedAccessException ex) { Console.WriteLine($"Access denied to directory: {subDirectory}. Skipping. Error: {ex.Message}"); } catch (Exception ex) { Console.WriteLine($"An error occurred while processing directory: {subDirectory}. Error: {ex.Message}"); } } } catch (UnauthorizedAccessException ex) { Console.WriteLine($"Access denied to directory: {directoryPath}. Skipping. Error: {ex.Message}"); } catch (Exception ex) { Console.WriteLine($"An error occurred while processing directory: {directoryPath}. Error: {ex.Message}"); } } private void ProcessFile(string filePath) { if (!extensions.Contains(Path.GetExtension(filePath))) { return; } Task task = new(() => { Console.WriteLine($"Processing file: {filePath}"); try { var fileHash = ComputeFileHash(filePath); if (!redundancies.ContainsKey(fileHash)) { long fileSize = new FileInfo(filePath).Length; redundancies.Add(fileHash, new Redundancy() { Hash = fileHash, FileSize = fileSize }); } redundancies[fileHash].Paths.Add(filePath); } catch (Exception ex) { Console.WriteLine($"Error processing file {filePath}: {ex.Message}"); } }); task.Start(); tasks.Add(task); } private string ComputeFileHash(string filePath) { using var sha256 = SHA256.Create(); using var stream = File.OpenRead(filePath); var hash = sha256.ComputeHash(stream); return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); } } }