A .NET keretrendszer beépítetten tartalmaz stream osztályokat ZIP és GZIP tömörítés kezeléséhez.
A GZIP a ZIP által használt Deflate algoritmus GNU implementációja. A GZIP fájlok a ZIP formátummal ellentétben csak egy fájl tárolására képesek és manapság leginkább HTTP/HTTPS kommunikáció esetén használtak a gyorsabb adatátvitel érdekében, de számos más helyen is fellelhető. Egyik ilyen felhasználása a PNG formátumban van.
A ZIP archívum formátum 1989-ben mutatkozott be, mai napig a legnépszerűbb tömörített archívum formátum, köszönhetően annak, hogy a tömörítő kódja az 1989-es kiadás óta Public Domain licenc alatt lett kiadva. Ez azt jelenti, hogy bárki készíthet ZIP tömörítőt anélkül, hogy az eredeti szerzőnek bármiféle jogdíjat fizetne. Továbbá terjesztési korlátozás sincs az ilyen licenc alatt kiadott kódon alapuló termékekre, mondhatni közkincsnek számítanak.
A tömörítő implementációk a .NET keretrendszerben a System.IO.Compression névtérben laknak, aminek a használatához egy dll referenciát kell hozzáadnunk a projektünkhöz. Ezt többféleképpen is megtehetjük, de talán a legegyszerűbb, ha a ‘Solution Explorerben’ a ‘References’ menüponton jobb kattintva a menüből az ‘Add Reference…’ lehetőséget választjuk.
A megnyíló ablakban a legegyszerűbb a szükséges dll fájlt megkeresni úgy, hogy a bal felső keresőbe beírjuk a Compression szót. Erre két találatot kapunk, a System.IO.Compression és a System.IO.Compression.Filesystem szerelvényt. Jelen példához mindkettőt hozzáadtam. Az utóbbi csak akkor szükséges, ha mappából szeretnénk ZIP fájlt készíteni, vagy ZIP-et szeretnénk kibontani és nem feltétlenül manuálisan, stream sorozatként kezelnénk.
GZIP tömörítés
A GZIP formátum használata igen egyszerű, lényegében a korábban ismertetett stream alapokon működik, A GzipStream egy Stream osztály fölé épülő újabb stream, ami segítségével ki vagy be tömöríteni tudjuk az adatfolyam tartalmát.
using System;
using System.IO;
using System.IO.Compression;
namespace PeldaTomoritesGzip
{
class Program
{
static void Main(string[] args)
{
using (var file = File.Create("test.gzip"))
{
using (var gZipStream = new GZipStream(file, CompressionMode.Compress))
{
using (var writer = new StreamWriter(gZipStream))
{
writer.WriteLine("Ez egy teszt szöveg");
}
}
}
using (var file = File.OpenRead("test.gzip"))
{
using (var gZipStream = new GZipStream(file, CompressionMode.Decompress))
{
using (var reader = new StreamReader(gZipStream))
{
Console.WriteLine(reader.ReadLine());
}
}
}
Console.ReadKey();
}
}
}
A program kimenete:
Ez egy teszt szöveg
A fenti példában újdonság a korábbi kódokhoz képest a GZipStream osztály megjelenése. Ennek a konstruktora két paramétert vár. Az első paraméter egy stream, amit a második paraméter által meghatározott módon vagy kitömörítünk, vagy ebbe íródik a tömörített adat(CompressionMode.Decompress vagy CompressionMode.Compress).
A sok using utasítás nem lenne kötelező, mivel a GZipStream Finalizere az alatta lévő stream-et is bezárja. Érdemes megjegyezni, hogy itt sem szabad elfelejteni a hibakezelést, ami a példaprogramból jelenleg kimaradt.
Brotli tömörítés
A Brotli tömörítés egy viszonylag új tömörítés, 2015-ben kapott RFC számot. Érdekessége, hogy magyar vonatkozású, mivel az algoritmus egyik fejlesztője Szabadka Zoltán. Kifejezetten webes átvitelre találták ki, főleg nagyobb (>= 1 MiB) méretű fájok esetén. .NET esetén a Core 2.2 verzió óta elérhető és .NET Framework alatt nem támogatott. Használata hasonló a Gzip tömörítéshez:
using System;
using System.IO;
using System.IO.Compression;
namespace pelda_tomorites_gzip
{
class Program
{
static void Main(string[] args)
{
using (var file = File.Create("test.br"))
{
using (var brotliStream = new BrotliStream(file, CompressionMode.Compress))
{
using (var writer = new StreamWriter(brotliStream))
{
writer.WriteLine("Ez egy teszt szöveg");
}
}
}
using (var file = File.OpenRead("test.br"))
{
using (var brotliStream = new BrotliStream(file, CompressionMode.Decompress))
{
using (var reader = new StreamReader(brotliStream))
{
Console.WriteLine(reader.ReadLine());
}
}
}
Console.ReadKey();
}
}
}
A példából látható, hogy a Gzip és a Brotli algoritmusok használata között csupán a használt Stream osztály nevében van különbség.
ZIP tömörítés
A ZIP fájlok kezelése kicsit másabb, mivel a ZIP egy komplex formátum abban az értelemben, hogy nem csak egy fájlt képes tárolni. Ezért nem teljesen stream módon kezelhető. Ezért a kezelő osztály nevében sem szerepel a stream szó. Helyette ZipArchive nevet viseli. Egy ilyen archívum bejegyzések sorozatából áll. Minden egyes bejegyzés rendelkezik névvel, elérési útvonallal (az elérési útvonal lényegében a mappa struktúrát kódolja), módosítási dátummal. A bejegyzéshez tartozó adatok stream formában érhetőek el.
A bejegyzéseket a ZipArchiveEntry írja le. Az alábbi példaprogram egy ZIP programozott létrehozását mutatja be.
using System;
using System.IO;
using System.IO.Compression;
namespace PeldaTomoritesZip
{
class Program
{
static void Main(string[] args)
{
using (var file = File.Create("test.zip"))
{
using (ZipArchive zip = new ZipArchive(file, ZipArchiveMode.Create))
{
ZipArchiveEntry entry = zip.CreateEntry("teszt.txt");
entry.LastWriteTime = DateTime.Now;
using (var entryStream = entry.Open())
{
using (var writer = new StreamWriter(entryStream))
{
writer.Write("teszt");
}
}
}
}
}
}
}
A kódrészlet kicsit macerásnak tűnhet, mert valójában az is. Éppen ezért a keretrendszerbe beépítettek egy ZipFile osztályt is, amivel komplett mappát tudunk becsomagolni az összes benne lévő almappával és fájllal együtt. Az osztály statikus metódusai:
public static void CreateFromDirectory(string sourceDirectoryName, string destinationArchiveFileName);
public static void CreateFromDirectory(string sourceDirectoryName, string destinationArchiveFileName, CompressionLevel compressionLevel, bool includeBaseDirectory);
public static void CreateFromDirectory(string sourceDirectoryName, string destinationArchiveFileName, CompressionLevel compressionLevel, bool includeBaseDirectory, Encoding entryNameEncoding);
ZIP fájl létrehozása a megadott mappából. A legegyszerűbb változatának két paramétere van. Egy bemeneti könyvtárnév és egy kimeneti ZIP fájlnév.
A négy paraméteres változat esetén a harmadik paraméter egy CompressionLevel típusú enum, ami a tömörítés mértékét határozza meg. Ez Optimal, Fastest vagy NoCompression értéket vehet fel.
A negyedik paraméter azt határozza meg, hogy a bementi könyvtár neve is belekerüljön-e a ZIP fájlba, vagy csak az azon belüli fájlok legyenek tárolva.
Ha az öt paraméteres változatot használjuk, akkor az utolsó paraméter a fájlnevek kódolását határozza meg. Erre akkor lehet szükségünk, ha egy igazán régi ZIP tömörítővel szeretnék kicsomagolni a fájlt, mivel 1989-ben még nem volt UTF kódolás.
public static void ExtractToDirectory(string sourceArchiveFileName, string destinationDirectoryName);
public static void ExtractToDirectory(string sourceArchiveFileName, string destinationDirectoryName, Encoding entryNameEncoding);
ZIP fájl kicsomagolása. Két paraméteres változata esetén az első paraméter az archívum neve, a második paraméter a cél mappa. A harmadik paraméter a fájlnév kódolást befolyásolja, ha ezt a változatot használjuk.
Archívumok kezelése
A ZIP fájlokat a Windows Millenium változattól fogva támogatja Tömörített Mappák néven, azonban a GZIP fájlok olvasásához nem tartalmaz beépített programot. Megoldást jelenthet például az ingyenesen letölthető és használható, 7-Zip nevű program, amely mindkét archívum típus létrehozásával és kitömörítésével megbirkózik. Letölteni a https://www.7-zip.org/ címről lehetséges.