Glengamoi (Forum) · AspHeute · .NET Heute (RSS-Suche) · AspxFiles (Wiki) · .NET Blogs

Eine Klasse für sich - die .NET Zip Library

Geschrieben von: Christoph Wille
Kategorie: .NET Allgemein

This printed page brought to you by AlphaSierraPapa

Das .NET Framework umfasst hunderte Klassen, doch etwas fehlt: es gibt keinerlei Klassen zur Komprimierung und Dekomprimierung von Zip Archiven. Diesem Fehlen kann aber mit der .NET Zip Library (#ziplib) abgeholfen werden - diese unterstützt sowohl das Zip als auch das GZip Format, ist gratis, und kommt mit C# Code inklusive.

Die #ziplib (SharpZipLib, ehemals NZipLib) kann von ic#code downgeloadet werden. Obwohl die Library selbst unter der GPL (GNU General Public License) vertrieben wird, darf man dank der Ausnahme die Library in Nicht-GPL Programmen einsetzen.

Verwendung in ASP.NET

Die Library ist als DLL Assembly kompiliert, und ist im verlinkten Download als Datei namens SharpZipLib.dll enthalten. Der erste Schritt ist also, sie in das bin Verzeichnis der Website zu verfrachten - dieser Vorgang wurde bereits im Artikel Eine Eurokonvertierungskomponente in C# erstellen beschrieben

Jetzt wo die Komponente dank XCOPY Deployment bereits registriert ist, kann sie auch schon verwendet werden. Dazu habe ich eine kleine ASP.NET Seite geschrieben, die den Inhalt eines Zip Archivs ausgibt: den Dateinamen, die Dateigröße, die komprimierte Größe. Der Sourcecode ist im Download des heutigen Artikels als ListZipContent.aspx enthalten:

<% @Page Language= "C#" %>
<% @Import Namespace="System.IO" %>
<% @Import Namespace="System.Text" %>
<% @Import Namespace="ICSharpCode.SharpZipLib.Zip" %>
<%
ZipInputStream s = new ZipInputStream(File.OpenRead("c:\\test.zip"));
ZipEntry theEntry = null;
StringBuilder strOutput = new StringBuilder();

while ((theEntry = s.GetNextEntry()) != null) 
{
  strOutput.Append("<tr><td>");
  strOutput.Append(theEntry.Name);
  strOutput.Append("</td><td>");
  strOutput.Append(theEntry.Size.ToString());
  strOutput.Append("</td><td>");
  strOutput.Append(theEntry.CompressedSize.ToString());
  strOutput.Append("</td></tr>\r\n");
}

s.Close(); // clean up the file resource immediately
%>

<table>
<tr><th>File name</th><th>Actual Size</th><th>Compressed Size</th></tr>
<%
  Response.Write(strOutput.ToString());
%>
</table>

Dieses Beispiel verwendet die Klassen aus dem ICSharpCode.SharpZipLib.Zip Namespace, deshalb muß ein entsprechendes Import Statement vorhanden sein. Eine genaue Beschreibung aller Namespaces und Klassen können Sie in der Hilfedatei Documentation.chm finden. Diese Dokumentation ist ähnlich zur .NET Framework Reference aufgebaut, das navigieren sollte also kein Problem sein.

In obigem Beispiel verwende ich die ZipInputStream Klasse, um auf eine bereits existierende (hardcodierte) Zip Datei zuzugreifen. Nach dem Öffnen des Archivs laufe ich mittels einer while Schleife alle Einträge (ZipEntry Klasse) durch, und puffere den generierten Tabelleninhalt in einem StringBuilder Objekt (siehe auch Artikel Die String Klasse in C#).

Die Ausgabe sieht wenig aufregend so aus, ist aber Beweis, daß es funktioniert wie geplant:

Dateien in Archiven betrachten

Jetzt haben wir eine Liste von Dateien - wie kommen wir aber an deren Inhalte? Sprich wie dekomprimieren wir die einzelnen Dateien? Hierzu ein modifiziertes Beispiel, das an der Kommandozeile läuft (ViewZipFile.cs):

using System;
using System.Text;
using System.IO;

using ICSharpCode.SharpZipLib.Zip;

class MainClass
{
  public static void Main(string[] args)
  {
    ZipInputStream s = new ZipInputStream(File.OpenRead(args[0]));
    ZipEntry theEntry;

    int nBytes = 2048;
    byte[] data = new byte[2048];

    while ((theEntry = s.GetNextEntry()) != null) 
    {
      Console.WriteLine(theEntry.Name);
      Console.Write("Eintrag anzeigen? (j/n)");

      if (Console.ReadLine() == "j") 
      {
        while((nBytes = s.Read(data, 0, data.Length))  > 0)
        {
           Console.Write(new ASCIIEncoding().GetString(data,0,nBytes));
        }
      }
      Console.WriteLine();
    }
    s.Close();
  }
}

Im Prinzip ist das Auslesen einer komprimierten Datei aus dem Zip Archiv nur der Read Befehl, den man von Streams sowieso schon kennt. Wir verarbeiten die erhaltenen Daten so, daß wir sie mittels ASCII Encoding an der Konsole ausgeben. Natürlich könnte man statt der Konvertierung die Daten in eine Datei auf der Festplatte schreiben.

Kompiliert wird diese Anwendung wie folgt (Annahme: NZipLib.dll liegt im gleichen Verzeichnis):

csc /target:exe /reference:SharpZipLib.dll ViewZipFile.cs

Der Aufruf erfolgt so:

viewzipfile c:\test.zip

Und schon kann man sich die Dateien im Zip Archiv ansehen.

Zip Archive erstellen

Auslesen ist ja leicht! Und wie steht's mit dem Erstellen eines Zip Archivs? Nun, sehen wir uns ein kleines Beispielprogramm an, das alle Dateien eines Unterverzeichnisses in eine Zip Datei schreibt (CreateZipFile):

using System;
using System.IO;

using ICSharpCode.SharpZipLib.Zip;

class MainClass
{
  public static void Main(string[] args)
  {
    // alle Dateien im angegebenen Ordner werden komprimiert
    string[] aFilenames = Directory.GetFiles(args[0]);
    
    // der Name der Zipdatei ist der zweite Parameter im Aufruf
    ZipOutputStream s = new ZipOutputStream(File.Create(args[1]));
    
    // Komprimierungslevel setzen: 0 [keine] - 9 [stärkste]
    s.SetLevel(5); 
    
    for (int i=0; i < aFilenames.Length; i++)
    {
      FileStream fs = File.OpenRead(aFilenames[i]);
      
      // im Normalfall allokiert man die Buffer im voraus
      // hier aus Klarheitsgründen pro Datei einmal
      byte[] buffer = new byte[fs.Length];
      fs.Read(buffer, 0, buffer.Length);

      // und jetzt schreiben wir einen ZipEntry & die Daten      
      ZipEntry entry = new ZipEntry(aFilenames[i]);
      s.PutNextEntry(entry);
      s.Write(buffer, 0, buffer.Length);
    }
    
    s.Finish();
    s.Close();
  }
}

Im Komprimierungsszenario arbeiten wir mit der ZipOutputStream Klasse, die uns bei der Erstellung des Archivs zur Seite steht. Im Prinzip ist alles ein umgekehrter Vorgang zum Entzippen: hier erstellen wir einen ZipEntry, und anstatt daß wir die Datei aus dem Archiv auslesen, schreiben wir sie in das Archiv.

Verwendet wird das Programm wie folgt:

createzipfile c:\verzeichnis c:\zipfile.zip

Ich denke daß das Erzeugen eines Archivs um nichts schwieriger ist als das Auslesen von Dateien aus einem Archiv.

Schlußbemerkung

Ich habe heute nur die Verwendung der Zip Klassen in der Library gezeigt. Allerdings werden die GZip Klassen völlig analog verwendet, da sie von denselben Basisklassen ableiten. Zip ahoi!

This printed page brought to you by AlphaSierraPapa

Download des Codes

Klicken Sie hier, um den Download zu starten.
http://www.aspheute.com/code/20011115.zip

Verwandte Artikel

Die String Klasse in C#
http:/www.aspheute.com/artikel/20000803.htm
Directory Browsing a la .NET
http:/www.aspheute.com/artikel/20000804.htm
Eine Eurokonvertierungskomponente in C# erstellen
http:/www.aspheute.com/artikel/20010123.htm

Links zu anderen Sites

#ZipLib (SharpZipLib) Download
http://www.icsharpcode.net/OpenSource/SharpZipLib/

 

©2000-2006 AspHeute.com
Alle Rechte vorbehalten. Der Inhalt dieser Seiten ist urheberrechtlich geschützt.
Eine Übernahme von Texten (auch nur auszugsweise) oder Graphiken bedarf unserer schriftlichen Zustimmung.