Ich habe nach einer einfachen Möglichkeit gesucht, eine Datei aus einem gepackten Arichv in einem Stream zu extrahieren und die Datei dann auszulesen.
Dazu habe ich eine einfache Schnittstelle erstellt - IArchive - über die man verschiedene Zip Bibliotheken implementieren kann. In diesem Beispiel habe ich das .NET Binding für 7zip bentuzt. Zu finden auf http://sevenzipsharp.codeplex.com/. Auf dieser Seite werden auch im Downloadbereich die Assembly SevenZipSharp.dll sowie die 7z.dll benötigt.
Zum Projekt muss die SevenZipSharl.dll als Referenz hinzugefügt werden und die 7z.dll ins Anwendungsverzeichnis kopiert werden.
IArchive besitzt eine einfache Funktion GetStream, die als ersten Parameter den relativen Pfad zur Datei im Archiv bekommt und als Zweiten einen Lambdaausdruck, der die Strategie zum Entpacken angibt. Von der Lambda Funktion wird eine von Stream abgeleitete Klasse zurückgegeben, die vom darunter liegenden Archivierungsprogram (in meinem Fall SevenZipSharp) benutzt wird, um die Daten zu entpacken.
In dem Beispiel wird ein MemoryStream verwendet, um einen schnellen Datenzugriff zu erhalten.
Ein weiterer Kandidaten zur Implementierung eines Packprogramms wäre DotNetZip http://dotnetzip.codeplex.com/ oder aus dem SharpDevelop Projekt die SharpZipLib http://sharpdevelop.net/OpenSource/SharpZipLib/
Last but not least, wäre eine einfache Implementierung und Kapselung von dem OpenXML SDK darunter vorstellbar.
Der Unten angefügte Code ist mit einem Beispielklasse zur Verwendung (MyApp) angegeben.
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using SevenZip;
public class MyApp
{
public MyApp()
{
var archivePath = @"C:\Users\Rainer\Downloads\dev\boo-0.9.1.3287-bin.zip";
var compressedArchive = new CompressedArchive(archivePath);
var settingsStream = getSettingsStreamFromArchive(compressedArchive);
var xmlSettingsDoc = createXmlDocumentFromStream(settingsStream);
configureAppFromXDocument(xmlSettingsDoc);
}
private XDocument createXmlDocumentFromStream(Stream stream)
{
var xmlReader = XmlReader.Create(stream);
return XDocument.Load(xmlReader);
}
private static Stream getSettingsStreamFromArchive(IArchive archive)
{
var relativePathInArchive = @"extras\rules.xml";
var settingsStream = archive.GetStream(relativePathInArchive, () => new MemoryStream() );
return settingsStream;
}
}
public interface IArchive
{
Stream GetStream(string pathToExtract, Func<Stream> outputStreamingStrategy);
}
public class CompressedArchive : IArchive
{
private readonly SevenZipExtractor zipExtractor;
public CompressedArchive(string archivePath)
{
zipExtractor = new SevenZipExtractor(archivePath);
}
public Stream GetStream(string pathToExtract, Func<Stream> outputStreamingStrategy)
{
if (outputStreamingStrategy == null)
throw new ArgumentNullException("outputStreamingStrategy");
if (pathToExtract == null)
throw new ArgumentNullException("pathToExtract");
var outputStream = outputStreamingStrategy();
zipExtractor.ExtractFile(pathToExtract, outputStream );
//in order to be used by another wrapping class (i.e. XmlReader), the stream has to be reset
outputStream.Position = 0;
return outputStream;
}
}
4 Kommentare zum Snippet