diff --git a/Test/Test/MD5Test/Azaza/azaza.txt.txt b/Test/Test/MD5Test/Azaza/azaza.txt.txt new file mode 100644 index 0000000..373bc1c --- /dev/null +++ b/Test/Test/MD5Test/Azaza/azaza.txt.txt @@ -0,0 +1 @@ +WFWFWEFWEFWVWwGVWvfegrebke eab fdaeio dferb rtnd dbaeb \ No newline at end of file diff --git a/Test/Test/MD5Test/Azaza/uzuzu.txt.txt b/Test/Test/MD5Test/Azaza/uzuzu.txt.txt new file mode 100644 index 0000000..d935460 --- /dev/null +++ b/Test/Test/MD5Test/Azaza/uzuzu.txt.txt @@ -0,0 +1 @@ +dfveerbergb serubn er8h ss bevbs wb \ No newline at end of file diff --git a/Test/Test/MD5Test/MD5Test.cs b/Test/Test/MD5Test/MD5Test.cs new file mode 100644 index 0000000..be7aef7 --- /dev/null +++ b/Test/Test/MD5Test/MD5Test.cs @@ -0,0 +1,29 @@ +namespace MD5Test; + +public class Tests +{ + [SetUp] + public void Setup() + { + } + + [Test] + public async Task ShouldReultRemainTheSameForComputeCheckSumForFile() + { + var firstCompute = await Test.MD5.ComputeCheckSumForFile("..//..//..//text.txt"); + var secondCompute = await Test.MD5.ComputeCheckSumForFile("..//..//..//text.txt"); + Assert.That(firstCompute, Is.EquivalentTo(secondCompute)); + } + + [Test] + public void ShouldDirectoryNotFoundException() + { + Assert.ThrowsAsync(() => Test.MD5.SequentiallyComputeCheckSumForDirectory("..//..//..//Ahaha")); + } + + [Test] + public void ShouldFileNotFoundException() + { + Assert.ThrowsAsync(() => Test.MD5.ComputeCheckSumForFile("Ahaha.txt")); + } +} diff --git a/Test/Test/MD5Test/MD5Test.csproj b/Test/Test/MD5Test/MD5Test.csproj new file mode 100644 index 0000000..d0f7b7d --- /dev/null +++ b/Test/Test/MD5Test/MD5Test.csproj @@ -0,0 +1,23 @@ + + + + net6.0 + enable + enable + + false + + + + + + + + + + + + + + + diff --git a/Test/Test/MD5Test/Usings.cs b/Test/Test/MD5Test/Usings.cs new file mode 100644 index 0000000..cefced4 --- /dev/null +++ b/Test/Test/MD5Test/Usings.cs @@ -0,0 +1 @@ +global using NUnit.Framework; \ No newline at end of file diff --git a/Test/Test/MD5Test/text.txt b/Test/Test/MD5Test/text.txt new file mode 100644 index 0000000..7aad374 --- /dev/null +++ b/Test/Test/MD5Test/text.txt @@ -0,0 +1 @@ +wevwevw34g vw834vw 8g3wv hvewrvewrvv ervuuw wev wbvwv sw se ef bef \ No newline at end of file diff --git a/Test/Test/Test.sln b/Test/Test/Test.sln new file mode 100644 index 0000000..e1d0f15 --- /dev/null +++ b/Test/Test/Test.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32505.173 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MD5", "Test\MD5.csproj", "{9CC20C6D-177D-42E0-BB20-9BD0A99E44A1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MD5Test", "MD5Test\MD5Test.csproj", "{4BAAADE4-FE65-4B66-BE72-FE99B382017A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9CC20C6D-177D-42E0-BB20-9BD0A99E44A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9CC20C6D-177D-42E0-BB20-9BD0A99E44A1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9CC20C6D-177D-42E0-BB20-9BD0A99E44A1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9CC20C6D-177D-42E0-BB20-9BD0A99E44A1}.Release|Any CPU.Build.0 = Release|Any CPU + {4BAAADE4-FE65-4B66-BE72-FE99B382017A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4BAAADE4-FE65-4B66-BE72-FE99B382017A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4BAAADE4-FE65-4B66-BE72-FE99B382017A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4BAAADE4-FE65-4B66-BE72-FE99B382017A}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C9040189-AFF7-479F-B79D-90D73122038F} + EndGlobalSection +EndGlobal diff --git a/Test/Test/Test/MD5.cs b/Test/Test/Test/MD5.cs new file mode 100644 index 0000000..fbb87c9 --- /dev/null +++ b/Test/Test/Test/MD5.cs @@ -0,0 +1,112 @@ +namespace Test; + +/// +/// Class representing the calculation of the check sum +/// +public class MD5 +{ + public static async Task ComputeCheckSumForFile(string path) + { + var md5 = System.Security.Cryptography.MD5.Create(); + if (!File.Exists(path)) + { + throw new FileNotFoundException(); + } + using var fileStream = new FileStream(path, FileMode.Open); + var bytes = await md5.ComputeHashAsync(fileStream); + return bytes; + } + + /// + /// Function for sequential calculation of the check sum of the directory + /// + /// Path to directory + /// + /// + public static async Task SequentiallyComputeCheckSumForDirectory(string pathToDirectory) + { + // Если директории не существует + + if (!Directory.Exists(pathToDirectory)) + { + throw new DirectoryNotFoundException(); + } + + // Берем имена файлов + var files = Directory.GetFiles(pathToDirectory); + + // Имена директорий + var directories = Directory.GetDirectories(pathToDirectory); + var list = new List<(byte[], string)>(); + + foreach(var directory in directories) + { + list.Add((await SequentiallyComputeCheckSumForDirectory(directory), directory)); + } + + foreach (var file in files) + { + list.Add((await ComputeCheckSumForFile(file), file)); + } + var directoryName = System.Text.Encoding.UTF8.GetBytes(Path.GetDirectoryName(pathToDirectory)!); + + // Сортируем для одинакового порядка полученных файлов + list.Sort(); + + foreach (var (lol, bytes) in list) + { + var result = new byte[bytes.Length + lol.Length]; + directoryName.CopyTo(result, 0); + lol.CopyTo(result, bytes.Length); + directoryName = result; + } + var md5 = System.Security.Cryptography.MD5.Create(); + return md5.ComputeHash(directoryName); + } + + /// + /// Function for parallel calculation of the check sum of the directory + /// + /// Path to directory + /// + /// + public static byte[] ParallelComputeCheckSumForDirectory(string pathToDirectory) + { + // Если директории не существует + if (!Directory.Exists(pathToDirectory)) + { + throw new DirectoryNotFoundException(); + } + + // Берем имена файлов + var files = Directory.GetFiles(pathToDirectory); + + // Имена директорий + var directories = Directory.GetDirectories(pathToDirectory); + + var list = new List<(byte[], string)>(); + + // Изначально хотел сделать как в домашке с матрицами, а именно дать каждому изпотоков какое то количество файлов на обработку + // После просто Task.Run(() => {...}) и объединять Task.Result + // Но так вроде выглядит проще + Parallel.ForEach(directories, directory => list.Add((ParallelComputeCheckSumForDirectory(directory), directory))); + Parallel.ForEach(files, file => list.Add((ParallelComputeCheckSumForDirectory(file), file))); + + // Сортируем для одинакового порядка полученных файлов + list.Sort(); + + // Первым идет имя директории + var directoryName = System.Text.Encoding.UTF8.GetBytes(Path.GetDirectoryName(pathToDirectory)!); + + + foreach (var (lol, bytes) in list) + { + var result = new byte[bytes.Length + lol.Length]; + directoryName.CopyTo(result, 0); + lol.CopyTo(result, bytes.Length); + directoryName = result; + } + var md5 = System.Security.Cryptography.MD5.Create(); + return md5.ComputeHash(directoryName); + } +} diff --git a/Test/Test/Test/MD5.csproj b/Test/Test/Test/MD5.csproj new file mode 100644 index 0000000..74abf5c --- /dev/null +++ b/Test/Test/Test/MD5.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/Test/Test/Test/Solution.cs b/Test/Test/Test/Solution.cs new file mode 100644 index 0000000..eb18554 --- /dev/null +++ b/Test/Test/Test/Solution.cs @@ -0,0 +1,52 @@ +using System.Diagnostics; + +if (args.Length < 1) +{ + Console.WriteLine("Количество аргументв должно быть не меньше 1"); + return; +} + + +static (IEnumerable, IEnumerable) Calculate(string path) +{ + var stopWatch = new Stopwatch(); + var numberOfIterations = 100; + var standardCalculations = new long[numberOfIterations]; + var parallelCalculations = new long[numberOfIterations]; + for (int i = 0; i < numberOfIterations; i++) + { + stopWatch.Reset(); + stopWatch.Start(); + var second = Test.MD5.SequentiallyComputeCheckSumForDirectory(path); + stopWatch.Stop(); + standardCalculations[i] = stopWatch.ElapsedMilliseconds; + + stopWatch.Reset(); + stopWatch.Start(); + var first = Test.MD5.ParallelComputeCheckSumForDirectory(path); + stopWatch.Stop(); + parallelCalculations[i] = stopWatch.ElapsedMilliseconds; + } + + return (standardCalculations, parallelCalculations); +} + +foreach (var path in args) +{ + var (standardCalculations, parallelCalculations) = Calculate(path); + var averageForStandardCalculations = Enumerable.Average(standardCalculations); + var averageForParallelCalculations = Enumerable.Average(parallelCalculations); + var varianceForStandardCalculations = Enumerable.Average(standardCalculations.Select(x => x * x)) - averageForStandardCalculations * averageForStandardCalculations; + var varianceForParallelCalculations = Enumerable.Average(parallelCalculations.Select(x => x * x)) - averageForParallelCalculations * averageForParallelCalculations; + //stream.WriteLine(); + //stream.Write($"{size} {Math.Round(averageForStandardCalculations, 3)} {Math.Round(Math.Sqrt(varianceForStandardCalculations), 3)} {Math.Round(averageForParallelCalculations, 3)} {Math.Round(Math.Sqrt(varianceForParallelCalculations), 3)}"); + Console.WriteLine($"Average operation time of standart : {Math.Round(averageForStandardCalculations, 3)}"); + Console.WriteLine($"Standard deviation operation time of standart: {Math.Round(Math.Sqrt(varianceForStandardCalculations), 3)}"); + Console.WriteLine(); + Console.WriteLine($"Average operation time of parallel : {Math.Round(averageForParallelCalculations, 3)}"); + Console.WriteLine($"Standard deviation operation time of parallel : {Math.Round(Math.Sqrt(varianceForParallelCalculations), 3)}"); + Console.WriteLine(); + Console.WriteLine(); + Console.WriteLine(); + +}