-
Notifications
You must be signed in to change notification settings - Fork 0
Lzw.homework3 #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 3 commits
3e33fb1
3ec3df7
4ad95c3
81ee53d
d1c015a
2b48a0b
fd7416e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| | ||
| Microsoft Visual Studio Solution File, Format Version 12.00 | ||
| # Visual Studio Version 17 | ||
| VisualStudioVersion = 17.1.32210.238 | ||
| MinimumVisualStudioVersion = 10.0.40219.1 | ||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LZW", "LZW\LZW.csproj", "{5DAEADDF-7108-4028-90E1-5C05C2034360}" | ||
| EndProject | ||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "LZWTest\Tests.csproj", "{455E760B-8592-4A15-BB37-A79DAE435B4C}" | ||
| EndProject | ||
| Global | ||
| GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
| Debug|Any CPU = Debug|Any CPU | ||
| Release|Any CPU = Release|Any CPU | ||
| EndGlobalSection | ||
| GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
| {5DAEADDF-7108-4028-90E1-5C05C2034360}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
| {5DAEADDF-7108-4028-90E1-5C05C2034360}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
| {5DAEADDF-7108-4028-90E1-5C05C2034360}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
| {5DAEADDF-7108-4028-90E1-5C05C2034360}.Release|Any CPU.Build.0 = Release|Any CPU | ||
| {455E760B-8592-4A15-BB37-A79DAE435B4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
| {455E760B-8592-4A15-BB37-A79DAE435B4C}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
| {455E760B-8592-4A15-BB37-A79DAE435B4C}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
| {455E760B-8592-4A15-BB37-A79DAE435B4C}.Release|Any CPU.Build.0 = Release|Any CPU | ||
| EndGlobalSection | ||
| GlobalSection(SolutionProperties) = preSolution | ||
| HideSolutionNode = FALSE | ||
| EndGlobalSection | ||
| GlobalSection(ExtensibilityGlobals) = postSolution | ||
| SolutionGuid = {7673691E-822C-4405-8F11-DE9C2BCBAE62} | ||
| EndGlobalSection | ||
| EndGlobal |
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,81 @@ | ||||||||||||||
| namespace Bor; | ||||||||||||||
|
|
||||||||||||||
| /// <summary> | ||||||||||||||
| /// A class representing the bor data structure | ||||||||||||||
| /// </summary> | ||||||||||||||
| public class Bor | ||||||||||||||
| { | ||||||||||||||
| /// <summary> | ||||||||||||||
| /// // A class representing the bor data structure | ||||||||||||||
| /// </summary> | ||||||||||||||
| private class Node | ||||||||||||||
| { | ||||||||||||||
| // Dictionary for storing characters for each node | ||||||||||||||
| public Dictionary<byte, Node> Nodes = new(); | ||||||||||||||
|
|
||||||||||||||
| // Code for each node | ||||||||||||||
| public int Code { get; set;} | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| // Bor root | ||||||||||||||
| private readonly Node root = new(); | ||||||||||||||
|
|
||||||||||||||
| // Bor size | ||||||||||||||
| public int Size { get; private set; } | ||||||||||||||
|
|
||||||||||||||
| private Node currentNode; | ||||||||||||||
|
|
||||||||||||||
| public int GetCode() | ||||||||||||||
| { | ||||||||||||||
| return currentNode.Code; | ||||||||||||||
| } | ||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
|
|
||||||||||||||
| public Bor() | ||||||||||||||
| { | ||||||||||||||
| root.Code = -1; | ||||||||||||||
|
|
||||||||||||||
| // Initialize the bor with numbers from 0 to 256 | ||||||||||||||
| for (int i = 0; i < 256; i++) | ||||||||||||||
| { | ||||||||||||||
| Node node = new(); | ||||||||||||||
| root.Nodes.Add((byte)i, node); | ||||||||||||||
| node.Code = Size; | ||||||||||||||
| Size++; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| // The current node is the root | ||||||||||||||
| currentNode = root; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /// <summary> | ||||||||||||||
| /// Function to add a byte | ||||||||||||||
| /// </summary> | ||||||||||||||
| /// <param name="byteToAdd"> byte to add </param> | ||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
| public void Add(byte byteToAdd) | ||||||||||||||
| { | ||||||||||||||
| Node node = new(); | ||||||||||||||
| currentNode?.Nodes.Add(byteToAdd, node); | ||||||||||||||
| currentNode = root; | ||||||||||||||
| node.Code = Size; | ||||||||||||||
| Size++; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /// <summary> | ||||||||||||||
| /// Is the byte contained in Current Node | ||||||||||||||
| /// </summary> | ||||||||||||||
| /// <param name="element"> Element to search </param> | ||||||||||||||
| /// <returns> True if there is such a byte. False if there is no such byte </returns> | ||||||||||||||
| public bool Contains(byte byteToSearch) => currentNode.Nodes.ContainsKey(byteToSearch); | ||||||||||||||
|
|
||||||||||||||
| /// <summary> | ||||||||||||||
| /// Function for moving to another node | ||||||||||||||
| /// </summary> | ||||||||||||||
| /// <param name="byteT">the byte to be moved to</param> | ||||||||||||||
| public void MoveIntoDesiredNode(byte byteToBeMovedTo) => currentNode = currentNode.Nodes[byteToBeMovedTo]; | ||||||||||||||
|
|
||||||||||||||
| /// <summary> | ||||||||||||||
| /// Function for moving to root | ||||||||||||||
| /// </summary> | ||||||||||||||
| public void MovedToRoot() => currentNode = root; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,150 @@ | ||||||||||||||||
| namespace LZW; | ||||||||||||||||
|
|
||||||||||||||||
| using System; | ||||||||||||||||
| using System.IO; | ||||||||||||||||
| using Bor; | ||||||||||||||||
|
|
||||||||||||||||
| /// <summary> | ||||||||||||||||
| /// A class representing the LZW algorithm | ||||||||||||||||
| /// </summary> | ||||||||||||||||
| public class LZW | ||||||||||||||||
| { | ||||||||||||||||
| //A function for determining the number of bytes needed to store a number | ||||||||||||||||
| private static int NumberOfBytes(int number) | ||||||||||||||||
| { | ||||||||||||||||
| if (number < 256) | ||||||||||||||||
| { | ||||||||||||||||
| return 1; | ||||||||||||||||
| } | ||||||||||||||||
| if (number < 65536) | ||||||||||||||||
| { | ||||||||||||||||
| return 2; | ||||||||||||||||
| } | ||||||||||||||||
| if (number < 16777216) | ||||||||||||||||
| { | ||||||||||||||||
| return 3; | ||||||||||||||||
| } | ||||||||||||||||
| return 4; | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| /// <summary> | ||||||||||||||||
| /// Function for file compression | ||||||||||||||||
| /// </summary> | ||||||||||||||||
| /// <param name="pathToFileToCompress">The path to the file to compress</param> | ||||||||||||||||
| public static void CompressFile(string pathToFileToCompress) | ||||||||||||||||
| { | ||||||||||||||||
|
|
||||||||||||||||
| string fileName = Path.GetFileNameWithoutExtension(pathToFileToCompress); | ||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
После открывающей фигурной скобки пустая строка не ставится |
||||||||||||||||
| fileName = $"{pathToFileToCompress}..//..//{fileName}.zipped"; | ||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Так мы теряем расширение файла в процессе запаковки/распаковки, что не очень. |
||||||||||||||||
|
|
||||||||||||||||
| // Name of the compressed file | ||||||||||||||||
| using FileStream fs = new(fileName, FileMode.Create); | ||||||||||||||||
|
|
||||||||||||||||
| // Reading all bytes from a file | ||||||||||||||||
| var stringToConvert = File.ReadAllBytes(pathToFileToCompress); | ||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Вообще, может быть плохой идеей читать файл в память целиком. Файлы бывают большие. Тем более что LZW может работать побайтово. Но это можно не править, для учебных целей вполне ок. |
||||||||||||||||
|
|
||||||||||||||||
| // Creating bor | ||||||||||||||||
| Bor bor = new(); | ||||||||||||||||
|
|
||||||||||||||||
| for (int i = 0; i < stringToConvert.Length; i++) | ||||||||||||||||
| { | ||||||||||||||||
| // If the byte is contained in the bor | ||||||||||||||||
| if (bor.Contains(stringToConvert[i])) | ||||||||||||||||
| { | ||||||||||||||||
| // Moving on to the next byte | ||||||||||||||||
| bor.MoveIntoDesiredNode(stringToConvert[i]); | ||||||||||||||||
| } | ||||||||||||||||
| // Otherwise, we add it to the bor | ||||||||||||||||
| else | ||||||||||||||||
| { | ||||||||||||||||
| // Taking the idex from the parent vertex and encode it | ||||||||||||||||
| var bytes = BitConverter.GetBytes(bor.GetCode()); | ||||||||||||||||
|
|
||||||||||||||||
| // Cut off the extra bytes | ||||||||||||||||
| // The required number of bytes is selected according to the size of the bor | ||||||||||||||||
| // Since among the numbers that need to be encoded there may be a bor size (index of the maximum vertex), | ||||||||||||||||
| // the number of bytes to store depends on the size of the bor. | ||||||||||||||||
| // Even a number requires fewer bytes, | ||||||||||||||||
| // it is written in a large number of bytes so that it can be decoded later. | ||||||||||||||||
| Array.Resize(ref bytes, NumberOfBytes(bor.Size - 1)); | ||||||||||||||||
| bor.Add(stringToConvert[i]); | ||||||||||||||||
| fs.Write(bytes); | ||||||||||||||||
|
|
||||||||||||||||
| // Going back to the last vertex | ||||||||||||||||
| i--; | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| // The last bytes that are already in the dictionary and that are not written in the loop | ||||||||||||||||
| var newbytes = BitConverter.GetBytes(bor.GetCode()); | ||||||||||||||||
| Array.Resize(ref newbytes, NumberOfBytes(bor.Size)); | ||||||||||||||||
| fs.Write(newbytes); | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| public static void DecompressFile(string pathToFile) | ||||||||||||||||
| { | ||||||||||||||||
|
|
||||||||||||||||
| string fileName = Path.GetFileNameWithoutExtension(pathToFile); | ||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||
| fileName = $"{pathToFile}..//..//{fileName}"; | ||||||||||||||||
|
|
||||||||||||||||
| // Create file | ||||||||||||||||
| using FileStream fs = new(fileName, FileMode.Create); | ||||||||||||||||
|
|
||||||||||||||||
| // Reading all bytes from a file | ||||||||||||||||
| byte[] stringToConvert = File.ReadAllBytes(pathToFile); | ||||||||||||||||
|
|
||||||||||||||||
| // Dictionary for decoding | ||||||||||||||||
| var dictionary = new Dictionary<int, byte[]>(); | ||||||||||||||||
|
|
||||||||||||||||
| for (int i = 0; i < 256; i++) | ||||||||||||||||
| { | ||||||||||||||||
| var byteArray = BitConverter.GetBytes(i); | ||||||||||||||||
| dictionary.Add(i, byteArray[0..1]); | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| int rightBorder = 0; | ||||||||||||||||
| int leftBorder = 0; | ||||||||||||||||
| bool flag = false; | ||||||||||||||||
|
|
||||||||||||||||
| while (leftBorder < stringToConvert.Length) | ||||||||||||||||
| { | ||||||||||||||||
| // The right border of the current subarray | ||||||||||||||||
| rightBorder = leftBorder + NumberOfBytes(dictionary.Count - 1) - 1; | ||||||||||||||||
|
|
||||||||||||||||
| // If the right border has gone beyond the edge, then we will make it the last byte | ||||||||||||||||
| rightBorder = rightBorder > stringToConvert.Length - 1 ? stringToConvert.Length - 1 : rightBorder; | ||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
| if (leftBorder > stringToConvert.Length - 1) | ||||||||||||||||
|
Comment on lines
+115
to
+130
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Две пустые строки подряд не принято |
||||||||||||||||
| { | ||||||||||||||||
| break; | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| // Converting bytes to int | ||||||||||||||||
| var bytes = new byte[4]; | ||||||||||||||||
| Array.Copy(stringToConvert, leftBorder, bytes, 0, NumberOfBytes(dictionary.Count - 1)); | ||||||||||||||||
| leftBorder = rightBorder + 1; | ||||||||||||||||
| int answer = BitConverter.ToInt32(bytes); | ||||||||||||||||
|
|
||||||||||||||||
| // If it is the first number | ||||||||||||||||
| if (!flag) | ||||||||||||||||
| { | ||||||||||||||||
| flag = true; | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| // Otherwise, we concatenate the last element with the first byte of the current one | ||||||||||||||||
| else | ||||||||||||||||
| { | ||||||||||||||||
| var newArray = new byte[dictionary[dictionary.Count - 1].Length + 1]; | ||||||||||||||||
| Array.Copy(dictionary[dictionary.Count - 1], newArray, dictionary[dictionary.Count - 1].Length); | ||||||||||||||||
| newArray[newArray.Length - 1] = dictionary[answer][0]; | ||||||||||||||||
| // Changing the value in the dictionary to the value we need | ||||||||||||||||
| dictionary[dictionary.Count - 1] = newArray; | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| // Adding a new element to the dictionary | ||||||||||||||||
| dictionary.Add(dictionary.Count, dictionary[answer]); | ||||||||||||||||
| fs.Write(dictionary[answer]); | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
|
|
||
| <PropertyGroup> | ||
| <OutputType>Exe</OutputType> | ||
| <TargetFramework>net6.0</TargetFramework> | ||
| <ImplicitUsings>enable</ImplicitUsings> | ||
| <Nullable>enable</Nullable> | ||
| </PropertyGroup> | ||
|
|
||
| </Project> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| namespace LZW; | ||
|
|
||
| public class Solution | ||
| { | ||
| static void Main(string[] args) | ||
| { | ||
| if (args.Length != 2) | ||
| { | ||
| throw new FileNotFoundException(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Не, а кто его поймает, если исключение бросается прямо из Main- а? Тут надо вежливо поругаться и рассказать, какие параметры программа ожидает. |
||
| } | ||
|
|
||
| string pathToFile = args[0]; | ||
|
|
||
| if (args[1] == "-c") | ||
| { | ||
| var file = new FileInfo(pathToFile); | ||
| long uncompressedFileSize = file.Length; | ||
| string fileName = Path.GetFileNameWithoutExtension(pathToFile); | ||
| fileName = $"{pathToFile}..\\..\\{fileName}.zipped"; | ||
| LZW.CompressFile(pathToFile); | ||
| file = new FileInfo(fileName); | ||
| long compressedFileSize = file.Length; | ||
| Console.WriteLine((float)(uncompressedFileSize) / (float)compressedFileSize); | ||
| return; | ||
| } | ||
|
|
||
| if (args[1] == "-u") | ||
| { | ||
| LZW.DecompressFile(pathToFile); | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. А если не -c и не -u, то надо что-то сказать пользователю |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,62 @@ | ||||||
| namespace Test; | ||||||
|
|
||||||
| using NUnit.Framework; | ||||||
| using Bor; | ||||||
| using System; | ||||||
|
|
||||||
| public class BorTest | ||||||
| { | ||||||
| Bor bor = new(); | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| [SetUp] | ||||||
| public void Setup() | ||||||
| { | ||||||
| bor = new(); | ||||||
| } | ||||||
|
|
||||||
| [Test] | ||||||
| public void ShouldExpectedTrueWhenContainsForBorWhereinCurrentNodeContainsThisNode() | ||||||
| { | ||||||
| bor.MoveIntoDesiredNode((byte)123); | ||||||
| bor.Add((byte)143); | ||||||
| bor.MoveIntoDesiredNode((byte)123); | ||||||
| Assert.IsTrue(bor.Contains((byte)143)); | ||||||
| } | ||||||
|
|
||||||
| [Test] | ||||||
| public void ShouldExpectedFalseWhenContainsForBorWhereinCurrentNodeContainsThisNode() | ||||||
| { | ||||||
| bor.MoveIntoDesiredNode((byte)123); | ||||||
| Assert.IsFalse(bor.Contains((byte)143)); | ||||||
| } | ||||||
|
|
||||||
| [Test] | ||||||
| public void ShouldBorSizeIncreaseByOneWhenAdd() | ||||||
| { | ||||||
| bor.MoveIntoDesiredNode((byte)123); | ||||||
| var size = bor.Size; | ||||||
| bor.Add((byte)12); | ||||||
| Assert.AreEqual(size + 1, bor.Size); | ||||||
| } | ||||||
|
|
||||||
| [Test] | ||||||
| public void ShouldWhenAddExistingNode() | ||||||
| { | ||||||
| Assert.Throws<ArgumentException>(() => bor.Add((byte)12)); | ||||||
| } | ||||||
|
|
||||||
| [Test] | ||||||
| public void ShouldExpectedCurrentRootEqualRootWhenMoveToRoot() | ||||||
| { | ||||||
| bor.MoveIntoDesiredNode((byte)123); | ||||||
| bor.MovedToRoot(); | ||||||
| Assert.AreEqual(-1, bor.GetCode()); | ||||||
| } | ||||||
|
|
||||||
| [Test] | ||||||
| public void ShouldExpectedCurrentRootWhenMoveIntoDesiredNode() | ||||||
| { | ||||||
| bor.MoveIntoDesiredNode((byte)123); | ||||||
| Assert.AreEqual(123, bor.GetCode()); | ||||||
| } | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| namespace Test; | ||
|
|
||
| using NUnit.Framework; | ||
| using System.IO; | ||
|
|
||
| public class LZWTests | ||
| { | ||
| [Test] | ||
| public void ShouldExpectedStringAreEqualWhenLZWForFile() | ||
| { | ||
| string filename = "..//..//..//Test.txt"; | ||
| LZW.LZW.CompressFile(filename); | ||
| string newFilename = "..//..//..//Test.zipped"; | ||
| LZW.LZW.DecompressFile(newFilename); | ||
| var firstString = File.ReadAllBytes(filename); | ||
| var secondString = File.ReadAllBytes("..//..//..//Test"); | ||
| Assert.AreEqual(firstString, secondString); | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. На одном файле работает. А на пустом, на текстовом/бинарном? |
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Он Trie