Freitag, 15. Oktober 2010

Komprimierung mit C#, Teil 1 - einfache Strings

Das .Net Studio bringt standardmäßig eine Klasse zur Komprimierung und Dekomprimierung von Daten im gzip Format mit sich, System.IO.Compression.GZipStream.
gzip ist ein gutes, offen verfügbares Format, welches, für technisch Interessierte, zur Komprimierung, ähnlich wie das ZIP - Format, den Deflate Algorithmus verwendet.
Die Klasse GZipStream ist ein Stream, wie herkömmliche Streams können mit ihr Daten geschrieben und gelesen werden, nur werden diese dabei direkt komprimiert bzw. dekomprimiert.
Als erstes Anwendungsbeispiel werde ich eine einfache Möglichkeit zur (De-)Komprimierung von Zeichenketten in (bzw. aus) einer Datei zeigen.
Für alle folgenden Codebeispiele werden die Anweisungen
using System.IO.Compression;
using System.IO;

benötigt.

Zuerst zur Komprimierung: Die Klasse GZipStream erwartet einen Stream im Konstruktor, in den die Daten hinein komprimiert werden sollen sowie den Komprimiermodus (hier CompressionMode.Compress).
Als Stream geben wir einen FileStream an, der auf die Datei zeigt, in welche der komprimierte String geschrieben werden soll.
Die Klasse GZipStream kann nur Bytes lesen und schreiben, daher muss der zu komprimierende String in ein byte - Array umgewandelt werden, was die Klasse ASCIIEncoding erledigt.
Das erhaltene Array wird dann mittels Write() geschrieben, der GZipStream komprimiert die Byte - Folge und schreibt sie über den FileStream in eine Datei.
Und so sieht der dazu passende Code aus:

private void CompressString(string uncompressedString)
{
    GZipStream CompressStream = new GZipStream(new FileStream(Application.StartupPath + "\\CompressedString.gz", FileMode.Create), CompressionMode.Compress);
    ASCIIEncoding Encoder = new ASCIIEncoding();
    byte[] UncompressedStringInBytes = Encoder.GetBytes(uncompressedString);
    CompressStream.Write(UncompressedStringInBytes, 0, UncompressedStringInBytes.Length);
    CompressStream.Close();
}

Der der Methode CompressString übergebene String wird in die Datei "CompressedString.gz" im Anwendungsverzeichnis geschrieben, .gz ist die Dateiendung für gzip - Dateien.
Die Datei kann mit herkömmlichen Entpackungsprogrammen (z.B. WinZip) entpackt werden, öffnet man die entpackte Datei mit einem Texteditor findet man den ursprünglichen String wieder.

Nun zum umgekehrten Fall, der Dekomprimierung des Strings aus der Datei:
Die Klasse GZipStream erwartet im Konstruktor wieder einen Stream, dieses Mal den Stream, aus welchem die komprimierten Daten gelesen werden sollen, und den Komprimiermodus (hier CompressionMode.Decompress).
Wir übergeben als Stream wieder einen FileStream.
Das Auslesen der Datei erfolgt nun durch eine Endlosschleife, in dieser wird jedes Mal über die Methode Read() des GZipStreams ein byte - Array in einen Buffer gelesen.
Die gelesenen Bytes werden über die Klasse ASCIIEncoding in einen String umgewandelt, wurden in einem Durchlauf weniger Bytes gelesen als der Buffer groß ist, ist die Datei offensichtlich zu Ende und die Schleife wird beendet.
Der Code:

        private string DecompressString(string compressedFile)
        {
            GZipStream DecompressStream = new GZipStream(new FileStream(Application.StartupPath + "\\CompressedString.gz", FileMode.Open), CompressionMode.Decompress);
            byte[] Buffer = new byte[4096];
            ASCIIEncoding Decoder = new ASCIIEncoding();
            int BytesReadCount = 0;
            string DecompressedString = "";

            while (true)
            {
                BytesReadCount = DecompressStream.Read(Buffer, 0, Buffer.Length);
                if (BytesReadCount != 0)
                {
                    DecompressedString += Decoder.GetString(Buffer, 0, BytesReadCount);
                }
                if (BytesReadCount < Buffer.Length)
                    break;
            }

            DecompressStream.Close();
            return (DecompressedString);
        }

Der Aufruf der beiden Methoden könnte zum Beispiel so aussehen:

CompressString("Dies ist ein Test 123456.");
string DecompressedString = DecompressString(Application.StartupPath + "\\CompressedString.gz");

Keine Kommentare:

Kommentar veröffentlichen