119 lines
4.0 KiB
C#
119 lines
4.0 KiB
C#
using System.Security.Cryptography;
|
|
|
|
namespace RedundancyFinder
|
|
{
|
|
public class Finder
|
|
{
|
|
List<Task> tasks = new List<Task>();
|
|
|
|
|
|
Dictionary<object, Redundancy> redundancies = new Dictionary<object, Redundancy>();
|
|
|
|
public Dictionary<object, Redundancy> 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();
|
|
}
|
|
}
|
|
}
|