Entpacken Sie Dateien programmgesteuert in .net

221

Ich versuche, eine komprimierte Datei programmgesteuert zu entpacken.

Ich habe versucht, die System.IO.Compression.GZipStreamKlasse in .NET zu verwenden, aber wenn meine App ausgeführt wird (eigentlich ein Komponententest), wird folgende Ausnahme angezeigt:

System.IO.InvalidDataException: Die magische Zahl im GZip-Header ist nicht korrekt. Stellen Sie sicher, dass Sie einen GZip-Stream übergeben.

Mir ist jetzt klar, dass eine .zipDatei nicht mit einer .gzDatei identisch ist , und das GZipist auch nicht mit Zip.

Da ich die Datei jedoch extrahieren kann, indem ich manuell auf die komprimierte Datei doppelklicke und dann auf die Schaltfläche "Alle Dateien extrahieren" klicke, sollte es meiner Meinung nach auch im Code eine Möglichkeit geben, dies zu tun.

Daher habe ich versucht, Process.Start()den Pfad zur komprimierten Datei als Eingabe zu verwenden. Dadurch öffnet meine App ein Fenster, in dem der Inhalt der komprimierten Datei angezeigt wird. Das ist alles in Ordnung, aber die App wird auf einem Server installiert, auf dem sich keiner befindet, um auf die Schaltfläche "Alle Dateien extrahieren" zu klicken.

Wie kann ich meine App dazu bringen, die Dateien in den komprimierten Dateien zu extrahieren?

Oder gibt es einen anderen Weg, es zu tun? Ich bevorzuge es im Code, ohne Bibliotheken oder Apps von Drittanbietern herunterzuladen. Die Sicherheitsabteilung ist nicht besonders begeistert davon ...

Petteri
quelle
12
Ihre Sicherheitsabteilung ist zufriedener damit, dass Sie Ihren eigenen Code für etwas schreiben, als eine Bibliothek zu verwenden, die debuggt und mit vermutlich vielen Augen betrachtet wurde? Sie können eine Bibliothek verwenden UND "im Code ausführen" (die Quelle abrufen und selbst kompilieren), aber ich sehe die Neuerfindung des Rads als größeres Problem an als alle Sicherheitsprobleme, die durch die Verwendung einer bewährten Bibliothek entstehen.
Jared Updike
10
@ Jared - Wenn das Management eine Idee im Kopf hat ...
Steven Evers
4
Wenn Sie ein Produkt eines Drittanbieters erhalten, besteht für die Sicherheitsabteilung ein geringeres Risiko. Laden Sie einfach dotnetzip herunter und benennen Sie es in "[Firmenname einfügen] .ziplibrary.dll" um
Simon

Antworten:

59

Wir haben SharpZipLib bei vielen Projekten erfolgreich eingesetzt. Ich weiß, dass es sich um ein Tool von Drittanbietern handelt, aber der Quellcode ist enthalten und könnte einen Einblick geben, wenn Sie das Rad hier neu erfinden.

Chris Conway
quelle
3
Ich habe versucht, SharpZipLib zu verwenden, und es hat gut funktioniert. Ich denke, ich muss sehen, ob das Verbot von Bibliotheken und APS von Drittanbietern eine strenge Regel oder eher eine Richtlinie ist.
Petteri
10
Ich weiß nichts über Ihr Unternehmen, aber ich habe immer die Erfahrung gemacht, dass es möglich ist, eine Ausnahme von dieser Art von Regel zu erhalten, wenn Sie eine Beschreibung des Geschäftsfalls schreiben, warum Sie die Ausnahme wünschen. Weisen Sie auf die Kosteneinsparungen gegenüber DIY sowie auf die Tatsache hin, dass die Quelle untersucht werden kann. Als Fallback erhalten Sie häufig die Erlaubnis, die Quelle zu verwenden, auch wenn Sie die DLL nicht verwenden können. Kompilieren Sie sie dann einfach selbst (oder zumindest die Teile, die Sie tatsächlich verwenden müssen ...).
RolandTumble
Sie müssen keine externen Bibliotheken verwenden, um Zip-Dateien zu dekomprimieren. Sie können Shell32 von System32 verwenden. Bitte sehen Sie stackoverflow.com/a/43066281/948694
arturn
490

Mit .NET 4.5 können Sie jetzt Dateien mit dem .NET Framework entpacken:

using System;
using System.IO;

namespace ConsoleApplication
{
  class Program
  {
    static void Main(string[] args)
    {
      string startPath = @"c:\example\start";
      string zipPath = @"c:\example\result.zip";
      string extractPath = @"c:\example\extract";

      System.IO.Compression.ZipFile.CreateFromDirectory(startPath, zipPath);
      System.IO.Compression.ZipFile.ExtractToDirectory(zipPath, extractPath);
    }
  }
}

Der obige Code stammt direkt aus der Microsoft-Dokumentation: http://msdn.microsoft.com/en-us/library/ms404280(v=vs.110).aspx

ZipFileist in der Baugruppe enthalten System.IO.Compression.FileSystem. (Danke Nateirvin ... siehe Kommentar unten)

bsara
quelle
118
Übrigens ZipFileist in der Baugruppe enthalten System.IO.Compression.FileSystem.
Nateirvin
73
Dies bedeutet, dass Sie der Framework-Assembly einen DLL-Verweis hinzufügen müssen System.IO.Compression.FileSystem.dll.
Chris Schiffhauer
Was ist mit .rar-Dateien? Der obige Code kann keine .rar-Dateien extrahieren.
Raghu
1
Ich habe dies in meiner asp.net-Kern-Web-API versucht. Der erste Eintrag wurde gut gelesen, aber beim zweiten Eintrag wird immer ein Fehler ausgegeben A local file header is corrupt. Irgendwas darüber?
SoftSan
Gleiches gilt für @SoftSan. Ich habe auch diesen Fehler bekommen. Was ist zu tun?
Rich
101

Für .Net 4.5+

Es ist nicht immer erwünscht, die unkomprimierte Datei auf die Festplatte zu schreiben. Als ASP.Net-Entwickler müsste ich mit den Berechtigungen herumspielen, um Rechte für meine Anwendung zum Schreiben in das Dateisystem zu gewähren. Durch die Arbeit mit Streams im Speicher kann ich all das umgehen und die Dateien direkt lesen:

using (ZipArchive archive = new ZipArchive(postedZipStream))
{
    foreach (ZipArchiveEntry entry in archive.Entries)
    {
         var stream = entry.Open();
         //Do awesome stream stuff!!
    }
}

Alternativ können Sie die dekomprimierte Datei weiterhin auf die Festplatte schreiben, indem Sie Folgendes aufrufen ExtractToFile():

using (ZipArchive archive = ZipFile.OpenRead(pathToZip))
{
    foreach (ZipArchiveEntry entry in archive.Entries)
    {
        entry.ExtractToFile(Path.Combine(destination, entry.FullName));
    }
} 

Um die ZipArchiveKlasse zu verwenden, müssen Sie einen Verweis auf den System.IO.CompressionNamespace und auf hinzufügen System.IO.Compression.FileSystem.

Mister Epic
quelle
8
Hat MSFT wirklich bis 4.5+ gebraucht, um einen nativen Dekompressor hinzuzufügen?
John Peters
2
@JohnPeters GZipStream wurde wieder in .Net 2.0 ( msdn.microsoft.com/en-us/library/… ) hinzugefügt . Es war jedoch nicht einfach, mit mehreren Dateien in einem Archiv im Speicher zu arbeiten. Das neue ZipArchiveObjekt passt gut zur Rechnung.
Mister Epic
1
Dies ist eine besonders gute Alternative, da sie das Entpacken ohne Verwendung des Dateisystems ermöglicht (in meinem Fall arbeite ich mit eingebetteten Ressourcen) und auch keine Erweiterung eines Drittanbieters ist.
ANeves
1
Warum sollte ich eine foreachSchleife verwenden, ExtractToFilewenn ich nur verwenden kann ZipFile.ExtractToDirectory(inputFile, outputDir);? Was ist der Vorteil der ersten Methode?
Der flauschige Roboter
1
In .NET 4.6.1 kann ich 'ZipArchive' nicht von 'System.IO.Compression.FileSystem' abrufen.
Ravi Anand
55

Kostenlose und keine externen DLL-Dateien. Alles ist in einer CS-Datei. Ein Download ist nur die CS-Datei, ein anderer Download ist ein sehr leicht verständliches Beispiel. Ich habe es heute versucht und kann nicht glauben, wie einfach das Setup war. Es funktionierte beim ersten Versuch, keine Fehler, kein Nichts.

https://github.com/jaime-olivares/zipstorer

Lukas
quelle
Sprach zu früh! Ich möchte die Dateien aus einem http-Download-Stream sofort aufblasen. Dies funktioniert nicht, da es Suchoperationen für den Stream verwendet :( Nun, dank des Quellcodes kann ich jetzt meinen eigenen ZipStream schreiben ...
oyophant
Die beste Lösung für mein Problem, da ich eine Updater-App schreibe und seitdem keine DLLs mehr in den Extraktionsprozess einbeziehen kann, müsste ich auch diese aktualisieren. Das ist gut. Danke!
Niklas
27

Verwenden Sie die DotNetZip-Bibliothek unter http://www.codeplex.com/DotNetZip

Klassenbibliothek und Toolset zum Bearbeiten von Zip-Dateien. Verwenden Sie VB, C # oder eine beliebige .NET-Sprache, um auf einfache Weise Zip-Dateien zu erstellen, zu extrahieren oder zu aktualisieren ...

DotNetZip funktioniert auf PCs mit dem vollständigen .NET Framework und kann auch auf mobilen Geräten ausgeführt werden, die das .NET Compact Framework verwenden. Erstellen und lesen Sie Zip-Dateien in VB, C # oder einer beliebigen .NET-Sprache oder einer beliebigen Skriptumgebung ...

Wenn Sie nur eine bessere DeflateStream- oder GZipStream-Klasse als Ersatz für die in .NET BCL integrierte Klasse wünschen, bietet DotNetZip diese ebenfalls an. DeflateStream und GZipStream von DotNetZip sind in einer eigenständigen Assembly verfügbar, die auf einem .NET-Port von Zlib basiert. Diese Streams unterstützen Komprimierungsstufen und bieten eine viel bessere Leistung als die integrierten Klassen. Es gibt auch einen ZlibStream, um das Set zu vervollständigen (RFC 1950, 1951, 1952) ...

Sam Axe
quelle
1
Hmmm ... Aber das ist eine Bibliothek von Drittanbietern!
Petteri
30
Wie sehr aufmerksam von dir. Wenn Sie nicht mehrere Monate damit verbringen möchten, Ihren eigenen Zip-Dateireader zu implementieren, ist dies die beste Option.
Sam Axe
Dieser ist viel besser als SharpZipLib
Kugel
5
Sie stellen mir Fragen zu einer Antwort, die fast 5 Jahre alt ist. Recherchiere. Ich bin sicher, Sie werden eine Antwort finden.
Sam Axe
2
@PhilCooper Dies ist eine sehr alte Frage, die ich zur Verwendung der integrierten System.IO.Compression.ZipFile empfehle. IIRC Ich hatte in der Vergangenheit wirklich schlechte Erfahrungen mit SharpZipLib, basierend auf meiner Erfahrung mit der Herstellung von Tausenden von Reißverschlüssen im laufenden Betrieb.
Kugel
9
String ZipPath = @"c:\my\data.zip";
String extractPath = @"d:\\myunzips";
ZipFile.ExtractToDirectory(ZipPath, extractPath);

Um die ZipFile-Klasse verwenden zu können, müssen Sie in Ihrem Projekt einen Verweis auf die Assembly System.IO.Compression.FileSystem hinzufügen

Mahadev Mähne
quelle
2

Standard-Zip-Dateien verwenden normalerweise den Deflate-Algorithmus.

Verwenden Sie DeflateStream, um Dateien zu extrahieren, ohne Bibliotheken von Drittanbietern zu verwenden. Sie benötigen etwas mehr Informationen zum Archivierungsformat für ZIP-Dateien, da Microsoft nur den Komprimierungsalgorithmus bereitstellt.

Sie können auch versuchen, zipfldr.dll zu verwenden. Es ist die Komprimierungsbibliothek von Microsoft (komprimierte Ordner aus dem Menü Senden an). Es scheint eine Com-Bibliothek zu sein, ist aber nicht dokumentiert. Möglicherweise können Sie es durch Experimente zum Laufen bringen.

Kenneth Cochran
quelle
Ich probiere die DeflateStream-Klasse aus. Dieses Mal erhalte ich System.IO.InvalidDataException: Blocklänge stimmt nicht mit seiner Ergänzung überein.
Petteri
Wie oben erwähnt, hat Microsoft nur den Algorithmus bereitgestellt. Sie benötigen auch Informationen zum Zip-Archivformat. en.wikipedia.org/wiki/ZIP_(file_format) sollte Ihnen den Einstieg erleichtern. In den Referenzen unten auf der Seite finden Sie Links zu detaillierteren Informationen.
Kenneth Cochran
2
Ich bin auch auf System.IO.Packaging.Package in .NET 3.5 gestoßen. Es sieht so aus, als ob es den Trick machen könnte, obwohl es nicht sehr intuitiv ist.
Kenneth Cochran
2

Ich benutze dies, um mehrere Dateien zu komprimieren oder zu entpacken. Das Regex-Zeug ist nicht erforderlich, aber ich verwende es, um den Datumsstempel zu ändern und unerwünschte Unterstriche zu entfernen. Ich verwende die leere Zeichenfolge in der Zeichenfolge "Komprimieren >> zipPath", um allen Dateien bei Bedarf etwas voranzustellen. Außerdem kommentiere ich normalerweise entweder Compress () oder Decompress () aus, je nachdem, was ich tue.

using System;
using System.IO.Compression;
using System.IO;
using System.Text.RegularExpressions;

namespace ZipAndUnzip
{
    class Program
    {
        static void Main(string[] args)
        {
            var directoryPath = new DirectoryInfo(@"C:\your_path\");

            Compress(directoryPath);
            Decompress(directoryPath);
        }

        public static void Compress(DirectoryInfo directoryPath)
        {
            foreach (DirectoryInfo directory in directoryPath.GetDirectories())
            {
                var path = directoryPath.FullName;
                var newArchiveName = Regex.Replace(directory.Name, "[0-9]{8}", "20130913");
                newArchiveName = Regex.Replace(newArchiveName, "[_]+", "_");
                string startPath = path + directory.Name;
                string zipPath = path + "" + newArchiveName + ".zip";

                ZipFile.CreateFromDirectory(startPath, zipPath);
            }

        }

        public static void Decompress(DirectoryInfo directoryPath)
        {
            foreach (FileInfo file in directoryPath.GetFiles())
            {
                var path = directoryPath.FullName;
                string zipPath = path + file.Name;
                string extractPath = Regex.Replace(path + file.Name, ".zip", "");

                ZipFile.ExtractToDirectory(zipPath, extractPath);
            }
        }


    }
}
Phyllip Hamby
quelle
Dies erfordert dot net 4.5 - nur eine Notiz, wie andere, die mit ZipFile geantwortet haben, notiert haben und ich immer noch 3.5 verwende.
Thronk
2

Das wird es tun System.IO.Compression.ZipFile.ExtractToDirectory(ZipName, ExtractToPath)

Ilya Kochetov
quelle
1

Von hier aus :

Komprimierte GZipStream-Objekte, die in eine Datei mit der Erweiterung .gz geschrieben wurden, können mit vielen gängigen Komprimierungswerkzeugen dekomprimiert werden. Diese Klasse bietet jedoch nicht von Natur aus Funktionen zum Hinzufügen oder Extrahieren von Dateien zu ZIP-Archiven.

RedWolves
quelle
1

Sie können alles in .NET 3.5 mit DeflateStream ausführen. In .NET 3.5 fehlt die Möglichkeit, die Dateikopfabschnitte zu verarbeiten, die zum Organisieren der komprimierten Dateien verwendet werden. PKWare hat diese Informationen veröffentlicht, mit denen Sie die Zip-Datei verarbeiten können, nachdem Sie die verwendeten Strukturen erstellt haben. Es ist nicht besonders belastend und eine gute Vorgehensweise beim Erstellen von Werkzeugen ohne Verwendung von Code von Drittanbietern.

Es ist keine einzeilige Antwort, aber es ist völlig machbar, wenn Sie bereit und in der Lage sind, sich die Zeit zu nehmen. Ich habe eine Klasse geschrieben, um dies in ein paar Stunden zu tun, und was ich daraus gemacht habe, ist die Möglichkeit, Dateien nur mit .NET 3.5 zu komprimieren und zu entpacken.

Michael Blake
quelle
0

Ich habe heute von diesem (Unzip-Paket auf NuGet) erfahren, da ich in DotNetZip auf einen schweren Fehler gestoßen bin und festgestellt habe, dass in den letzten zwei Jahren nicht wirklich so viel an DotNetZip gearbeitet wurde.

Das Unzip-Paket ist schlank und hat die Arbeit für mich erledigt - es hatte nicht den Fehler, den DotNetZip hatte. Außerdem war es eine relativ kleine Datei, die sich bei der eigentlichen Dekomprimierung auf die Microsoft BCL stützte. Ich konnte leicht Anpassungen vornehmen, die ich brauchte (um den Fortschritt beim Dekomprimieren verfolgen zu können). Ich empfehle es.

Per Lundberg
quelle
0

Aus eingebetteten Ressourcen:

using (Stream _pluginZipResourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(programName + "." + "filename.zip"))
{
    using (ZipArchive zip = new ZipArchive(_pluginZipResourceStream))
    {
        zip.ExtractToDirectory(Application.StartupPath);
    }
}
Steve Rousseau
quelle
0

Bisher habe ich cmd-Prozesse verwendet, um eine ISO-Datei zu extrahieren, sie in einen temporären Pfad vom Server zu kopieren und auf einem USB-Stick zu extrahieren. Kürzlich habe ich festgestellt, dass dies perfekt mit ISO-Geräten funktioniert, die weniger als 10 GB groß sind. Für eine ISO wie 29 GB bleibt diese Methode irgendwie hängen.

    public void ExtractArchive()
    {
        try
        {

            try
            {
                Directory.Delete(copyISOLocation.OutputPath, true); 
            }
            catch (Exception e) when (e is IOException || e is UnauthorizedAccessException)
            {
            }

            Process cmd = new Process();
            cmd.StartInfo.FileName = "cmd.exe";
            cmd.StartInfo.RedirectStandardInput = true;
            cmd.StartInfo.RedirectStandardOutput = true;
            cmd.StartInfo.CreateNoWindow = true;
            cmd.StartInfo.UseShellExecute = false;
            cmd.StartInfo.WindowStyle = ProcessWindowStyle.Normal;

            //stackoverflow
            cmd.StartInfo.Arguments = "-R";

            cmd.Disposed += (sender, args) => {
                Console.WriteLine("CMD Process disposed");
            };
            cmd.Exited += (sender, args) => {
                Console.WriteLine("CMD Process exited");
            };
            cmd.ErrorDataReceived += (sender, args) => {
                Console.WriteLine("CMD Process error data received");
                Console.WriteLine(args.Data);
            };
            cmd.OutputDataReceived += (sender, args) => {
                Console.WriteLine("CMD Process Output data received");
                Console.WriteLine(args.Data);
            };

            //stackoverflow


            cmd.Start();

            cmd.StandardInput.WriteLine("C:");
            //Console.WriteLine(cmd.StandardOutput.Read());
            cmd.StandardInput.Flush();

            cmd.StandardInput.WriteLine("cd C:\\\"Program Files (x86)\"\\7-Zip\\");
            //Console.WriteLine(cmd.StandardOutput.ReadToEnd());
            cmd.StandardInput.Flush();

            cmd.StandardInput.WriteLine(string.Format("7z.exe x -o{0} {1}", copyISOLocation.OutputPath, copyISOLocation.TempIsoPath));
            //Console.WriteLine(cmd.StandardOutput.ReadToEnd());
            cmd.StandardInput.Flush();
            cmd.StandardInput.Close();
            cmd.WaitForExit();
            Console.WriteLine(cmd.StandardOutput.ReadToEnd());
            Console.WriteLine(cmd.StandardError.ReadToEnd());
Răzvan Bălan
quelle
0

Sie können die Info-unzip- Befehlszeile cod verwenden. Sie müssen nur unzip.exe von der offiziellen Info-unzip-Website herunterladen.

 internal static void Unzip(string sorcefile)
    {
        try
        {
            AFolderFiles.AFolderFilesDelete.DeleteFolder(TempBackupFolder); // delete old folder   
            AFolderFiles.AFolderFilesCreate.CreateIfNotExist(TempBackupFolder); // delete old folder   
           //need to Command command also to export attributes to a excel file
            System.Diagnostics.Process process = new System.Diagnostics.Process();
            System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
            startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; // window type
            startInfo.FileName = UnzipExe;
            startInfo.Arguments = sorcefile + " -d " + TempBackupFolder;
            process.StartInfo = startInfo;
            process.Start();
            //string result = process.StandardOutput.ReadToEnd();
            process.WaitForExit();
            process.Dispose();
            process.Close();
        }
        catch (Exception ex){ throw ex; }
    }        
Arun Kumar
quelle