Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
image: Visual Studio 2019

build_script:
- For /R %%I in (*.sln) do dotnet test %%I

test: off
31 changes: 31 additions & 0 deletions hw2LZW/hw2LZW.sln
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 16
VisualStudioVersion = 16.0.31005.135
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hw2LZW", "hw2LZW\Hw2LZW.csproj", "{956FF906-65B8-45A7-AEEC-0C4F4D47EF5D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "hw2Lzw.Test", "hw2LzwTest\hw2Lzw.Test.csproj", "{705F21DF-850F-439F-BF37-F0F8EF554073}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{956FF906-65B8-45A7-AEEC-0C4F4D47EF5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{956FF906-65B8-45A7-AEEC-0C4F4D47EF5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{956FF906-65B8-45A7-AEEC-0C4F4D47EF5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{956FF906-65B8-45A7-AEEC-0C4F4D47EF5D}.Release|Any CPU.Build.0 = Release|Any CPU
{705F21DF-850F-439F-BF37-F0F8EF554073}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{705F21DF-850F-439F-BF37-F0F8EF554073}.Debug|Any CPU.Build.0 = Debug|Any CPU
{705F21DF-850F-439F-BF37-F0F8EF554073}.Release|Any CPU.ActiveCfg = Release|Any CPU
{705F21DF-850F-439F-BF37-F0F8EF554073}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DB7EE293-FCD3-4437-92C9-C3ABFADE5DE7}
EndGlobalSection
EndGlobal
105 changes: 105 additions & 0 deletions hw2LZW/hw2LZW/LZW.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
using System.Collections;
using System.IO;

namespace Hw2LZW
{
/// <summary>
/// класс для сжатия и разжатия
/// </summary>
public static class LZW
{
private static int GetCountOfBytes(byte[] array)
{
for (int i = array.Length - 1; i >= 0; i--)
{
if (array[i] != 0)
{
return i + 1;
}
}
return 1;
}

This comment was marked as resolved.


/// <summary>
/// функция сжатия файла
/// </summary>
/// <param name="pathFile">путь до файла, который будем сжимать</param>
public static void Compress(string pathFile)
{
using var file = new FileStream(pathFile, FileMode.Open);
var trie = new Trie();
var codes = new Queue<int>();
for (int i = 0; i < file.Length; ++i)
{
var byter = (byte)file.ReadByte();
var codeOfBytes = trie.IsAdd(byter);
if (codeOfBytes != -1)
{
codes.Enqueue(codeOfBytes);
trie.IsAdd(byter);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

И снова добавляем байт в дерево? Хм, зачем?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Надо придумать и написать этому рациональное объяснение. В реальном проекте нельзя просто взять и проигнорировать комментарий ревьюера.

}
}
codes.Enqueue(trie.GetCode());
var countOfBytes = GetCountOfBytes(BitConverter.GetBytes(trie.CountCodes));
using var fileZipped = new FileStream(pathFile + ".zipped", FileMode.CreateNew);
fileZipped.WriteByte((byte)countOfBytes);
var size = codes.Count;
for (int i = 0; i < size; i++)
{
var helpArray = BitConverter.GetBytes(codes.Dequeue());
fileZipped.Write(helpArray, 0, countOfBytes);
}
}

private static Hashtable InitializeHashtable()
{
var hashtable = new Hashtable();
for (int i = 0; i < 256; i++)
{
hashtable.Add(i, new byte[] { (byte)i });
}
return hashtable;
}

private static void AddLastSymbol(int code, Hashtable hashtable)
{
var bytes = (byte[])hashtable[code];
var previous = (byte[])hashtable[hashtable.Count - 1];
previous[previous.Length - 1] = bytes[0];
}

/// <summary>
/// функция для разжатия
/// </summary>
/// <param name="pathFile">путь до сжатого файла</param>
public static void Decompress(string pathFile)
{
var hashtable = InitializeHashtable();
var codes = hashtable.Count;
using var fileZipped = new FileStream(pathFile, FileMode.Open);
using var file = new FileStream(pathFile.Substring(0, pathFile.Length - 7), FileMode.OpenOrCreate);
int maxLength = fileZipped.ReadByte();
for (int i = 0; i < fileZipped.Length - 1; i += maxLength)
{
var codeInBytes = new byte[4];
for (int j = 0; j < maxLength; ++j)
{
codeInBytes[j] = (byte)fileZipped.ReadByte();
}
var code = BitConverter.ToInt32(codeInBytes, 0);
if (i != 0)
{
AddLastSymbol(code, hashtable);
}
var bytesArray = (byte[])hashtable[code];
var copyBytesArray = new byte[bytesArray.Length + 1];
Array.Copy(bytesArray, copyBytesArray, bytesArray.Length);
hashtable.Add(codes, copyBytesArray);
codes++;
file.Write(bytesArray);
}
}
}
}
34 changes: 34 additions & 0 deletions hw2LZW/hw2LZW/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
using System.IO;

namespace Hw2LZW
{
class Program
{
static void Main(string[] args)
{
if (args.Length != 2)
{
Console.WriteLine("Ошибка ввода!");
return;
}
if (args[1] == "-c")
{
LZW.Compress(args[0]);
var compressedFileSize = new FileInfo(args[0]);
var decompressedFileSize = new FileInfo(args[0] + ".zipped");
Comment on lines +18 to +19
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Наоборот же :)

Console.WriteLine($"Коэффициент сжатия: x {(double)compressedFileSize.Length / decompressedFileSize.Length}");
}
else if (args[1] == "-u")
{
LZW.Decompress(args[0]);
Console.WriteLine("Файл разжат!");
}
else
{
Console.WriteLine("Ошибка ввода!");
return;
}
}
}
}
107 changes: 107 additions & 0 deletions hw2LZW/hw2LZW/Trie.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
using System;
using System.Collections.Generic;

namespace Hw2LZW
{
/// <summary>
/// вспомогательный класс для реализация Lzw
/// </summary>
public class Trie
{
private class Node
{
public byte Bytes { get; }

public bool IsUsed { get; set; }

public int IdByte;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Я пишу "у этих свойств видимость уж слишком широкая, сеттер можно было убрать", а Вы такой "о, почему бы не превратить свойство в public-поле?". Типа "сгорел сарай, гори и хата"? Нет, не прокатит.


public int CodeBytes { get; set; }

public Dictionary<byte, Node> Sons;

public Node(byte bytes, int codeByte, bool isUsed)
{
IsUsed = isUsed;
Bytes = bytes;
IdByte = codeByte;
Sons = new Dictionary<byte, Node>();
}

public Node IsFind(byte value)
=> Sons.TryGetValue(value, out Node node) ? node : null;
}

private Node root = new Node(0, 0, false);

private Node runner;

public Trie()
{
for (int i = 0; i < 256; ++i)
{
InitRoot((byte)i, i);
}
runner = root;
}

public int CountCodes { get; set; }

private void InitRoot(byte idSymbol, int index)
{

var son = new Node(idSymbol, index, false);
root.Sons.Add(idSymbol, son);
son.CodeBytes = CountCodes;
CountCodes++;
}

private bool CheckAdd(byte value, Node node)
=> node.IsFind(value) == null;

public int LastCode { get; set; }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

По-хорошему, к свойствам (особенно с неочевидными названиями, как это) тоже надо комментарии

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Не исправлено


/// <summary>
/// функция добавления
/// </summary>
/// <param name="value">байт, который хотим добавить</param>
/// <returns>если такой байт уже есть, то вернем "-1"</returns>
public int IsAdd(byte value)
{
if (runner == root)
{
var check = runner.Sons[value];
if (!check.IsUsed)
{
check.IsUsed = true;
runner = runner.Sons[value];
LastCode = runner.Bytes;
return -1;
}
}
var isCheck = CheckAdd(value, runner);
if (isCheck)
{
var son = new Node(value, CountCodes, true);
son.CodeBytes = CountCodes;
CountCodes++;
runner.Sons.Add(value, son);
runner = root;
return LastCode;
}
else
{
runner = runner.Sons[value];
LastCode = runner.CodeBytes;
return -1;
}
}

/// <summary>
/// функция для возврата кода у узла
/// </summary>
/// <returns>возвращается код узла</returns>
public int GetCode()
=> runner.Bytes;
}
}
8 changes: 8 additions & 0 deletions hw2LZW/hw2LZW/hw2LZW.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>

</Project>
53 changes: 53 additions & 0 deletions hw2LZW/hw2LzwTest/LZWTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using NUnit.Framework;
using System.IO;

namespace hw2LzwTest
{
[TestFixture]
public class Tests
{
private bool Compare(string path1, string path2)
{
using FileStream file1 = File.OpenRead(path1);
using FileStream file2 = File.OpenRead(path2);
if (file1.Length != file2.Length)
{
return false;
}
for (int i = 0; i < file1.Length; ++i)
{
if (file1.ReadByte() != file2.ReadByte())
{
return false;
}
}
return true;
}

[TestCase]
public void LZWWithTxt()
{
string path1 = "..\\..\\..\\TestTxt.txt";
string path2 = "..\\..\\..\\TestTxtCopy.txt";
Comment on lines +30 to +31

This comment was marked as resolved.

File.Copy(path1, path2);
Hw2LZW.LZW.Compress(path1);
Hw2LZW.LZW.Decompress(path1 + ".zipped");
File.Delete(path1 + ".zipped");
Assert.IsTrue(Compare(path1, path2));
File.Delete(path2);
}

[TestCase]
public void LZWWithImg()
{
string path1 = "..\\..\\..\\TestImg.jpg";
string path2 = "..\\..\\..\\TestImgCopy.jpg";
File.Copy(path1, path2);
Hw2LZW.LZW.Compress(path1);
Hw2LZW.LZW.Decompress(path1 + ".zipped");
File.Delete(path1 + ".zipped");
Assert.IsTrue(Compare(path1, path2));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Я проделал это вручную и, если удалить исходный TestImg.jpg, получил:
TestImg

Есть подозрение, что тест проходит только потому, что TestImg.jpg уже существует, а распаковщик не перезаписывает файл до конца (то есть в хвосте остаются байты оригинального изображения).

File.Delete(path2);
}
}
}
Binary file added hw2LZW/hw2LzwTest/TestImg.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions hw2LZW/hw2LzwTest/TestTxt.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
sleep and code
eat and code
walk and coee
19 changes: 19 additions & 0 deletions hw2LZW/hw2LzwTest/hw2Lzw.Test.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\hw2LZW\Hw2LZW.csproj" />
</ItemGroup>

</Project>