Décompressez les fichiers par programme dans .net

221

J'essaie de décompresser par programme un fichier zippé.

J'ai essayé d'utiliser la System.IO.Compression.GZipStreamclasse en .NET, mais lorsque mon application s'exécute (en fait un test unitaire), j'obtiens cette exception:

System.IO.InvalidDataException: le nombre magique dans l'en-tête GZip n'est pas correct. Assurez-vous que vous passez dans un flux GZip ..

Je me rends compte maintenant qu'un .zipfichier n'est pas le même qu'un .gzfichier, et ce GZipn'est pas la même chose que Zip.

Cependant, comme je suis capable d'extraire le fichier en double-cliquant manuellement sur le fichier compressé puis en cliquant sur le bouton "Extraire tous les fichiers", je pense qu'il devrait également y avoir un moyen de le faire dans le code.

Par conséquent, j'ai essayé d'utiliser Process.Start()avec le chemin d'accès au fichier compressé en entrée. Cela amène mon application à ouvrir une fenêtre affichant le contenu du fichier compressé. C'est très bien, mais l'application sera installée sur un serveur sans aucun pour cliquer sur le bouton "Extraire tous les fichiers".

Alors, comment puis-je obtenir mon application pour extraire les fichiers dans les fichiers compressés?

Ou existe-t-il une autre façon de procéder? Je préfère le faire en code, sans télécharger de bibliothèques ou d'applications tierces; le service de sécurité n'a pas trop envie de ça ...

Petteri
la source
12
Votre service de sécurité préfère que vous écriviez votre propre code pour quelque chose que d'utiliser une bibliothèque qui a été déboguée et examinée par de nombreux yeux? Vous pouvez utiliser une bibliothèque ET "le faire dans du code" (obtenir la source et la compiler vous-même) mais je considère que réinventer la roue est un problème plus important que tout problème de sécurité provoqué par l'utilisation d'une bibliothèque éprouvée.
Jared Updike
10
@Jared - Quand la direction a une idée en tête ...
Steven Evers
4
Il y a moins de risques pour le service de sécurité si vous obtenez un produit tiers. Téléchargez simplement dotnetzip et renommez-le "[insérer le nom de la société] .ziplibrary.dll"
Simon

Réponses:

59

Nous avons utilisé SharpZipLib avec succès sur de nombreux projets. Je sais que c'est un outil tiers, mais le code source est inclus et pourrait fournir un aperçu si vous choisissez de réinventer la roue ici.

Chris Conway
la source
3
J'ai essayé d'utiliser SharpZipLib et cela a bien fonctionné. Je suppose que je vais devoir voir si l'interdiction des libs et apss tiers est une règle stricte ou plus d'une ligne directrice.
Petteri
10
Je ne connais pas votre entreprise, mais mon expérience a toujours été qu'il est possible d'obtenir une exception à ce type de règle si vous rédigez une description de l' analyse de rentabilisation expliquant pourquoi vous voulez l'exception. Soulignez les économies de coûts par rapport au bricolage, ainsi que le fait que la source peut être examinée. En guise de solution de rechange, vous pouvez souvent obtenir la permission d'utiliser la source même s'ils ne vous permettent pas d'utiliser la DLL - puis compilez-la vous-même (ou au moins les parties que vous devez réellement utiliser ...).
RolandTumble
Vous n'avez pas besoin d'utiliser des bibliothèques externes pour décompresser les fichiers zip, vous pouvez utiliser Shell32 de System32. Veuillez voir stackoverflow.com/a/43066281/948694
arturn
490

Avec .NET 4.5, vous pouvez désormais décompresser des fichiers à l'aide du framework .NET:

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);
    }
  }
}

Le code ci-dessus provient directement de la documentation de Microsoft: http://msdn.microsoft.com/en-us/library/ms404280(v=vs.110).aspx

ZipFileest contenu dans l'assemblage System.IO.Compression.FileSystem. (Merci nateirvin ... voir le commentaire ci-dessous)

bsara
la source
118
BTW, ZipFileest contenu dans l'assemblage System.IO.Compression.FileSystem.
nateirvin
73
Ce qui signifie que vous devez ajouter une référence DLL à l'assembly d'infrastructure System.IO.Compression.FileSystem.dll.
Chris Schiffhauer
Qu'en est-il des fichiers .rar. le code ci-dessus ne parvient pas à extraire les fichiers .rar.
Raghu
1
J'ai essayé cela dans mon API web asp.net, il lisait bien la première entrée, mais à la deuxième entrée, il donnait toujours une erreur A local file header is corrupt. Mais quoi que ce soit à ce sujet?
SoftSan
Même chose avec @SoftSan. J'ai aussi eu cette erreur. Que faire?
Rich
101

Pour .Net 4.5+

Il n'est pas toujours souhaitable d'écrire le fichier non compressé sur le disque. En tant que développeur ASP.Net, je devrais jouer avec les autorisations pour accorder des droits pour que mon application écrive sur le système de fichiers. En travaillant avec des flux en mémoire, je peux contourner tout cela et lire les fichiers directement:

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

Alternativement, vous pouvez toujours écrire le fichier décompressé sur le disque en appelant ExtractToFile():

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

Pour utiliser la ZipArchiveclasse, vous devrez ajouter une référence à l' System.IO.Compressionespace de noms et à System.IO.Compression.FileSystem.

Monsieur Epic
la source
8
At-il vraiment fallu MSFT jusqu'à 4.5+ pour ajouter un décompresseur natif?
John Peters
2
@JohnPeters GZipStream a été ajouté à nouveau dans .Net 2.0 ( msdn.microsoft.com/en-us/library/… ). Cependant, cela ne facilitait pas le travail avec plusieurs fichiers dans une archive en mémoire. Le nouvel ZipArchiveobjet correspond parfaitement à la facture.
Mister Epic
1
C'est une alternative particulièrement bonne car elle permet de décompresser sans utiliser le système de fichiers (dans mon cas, je travaille avec des ressources intégrées), et ce n'est pas non plus une extension tierce.
ANeves
1
Pourquoi devrais-je utiliser une foreachboucle ExtractToFilequand je peux simplement utiliser ZipFile.ExtractToDirectory(inputFile, outputDir);Quel est l'avantage de la première méthode?
The Fluffy Robot
1
dans .NET 4.6.1 je ne suis pas en mesure d'obtenir «ZipArchive» à partir de «System.IO.Compression.FileSystem», une idée?
Ravi Anand
55

Gratuit et aucun fichier DLL externe. Tout est dans un seul fichier CS. Un téléchargement n'est que le fichier CS, un autre téléchargement est un exemple très facile à comprendre. Je viens de l'essayer aujourd'hui et je ne peux pas croire à quel point la configuration était simple. Cela a fonctionné du premier coup, pas d'erreurs, rien.

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

Lukas
la source
Parlé trop tôt! Je souhaite gonfler instantanément les fichiers d'un flux de téléchargement http. Cela ne fonctionne pas car il utilise les opérations Seek sur le flux :( Eh bien, grâce au code source, je peux écrire mon propre ZipStream maintenant ...
oyophant
la meilleure solution à mon problème, car je suis en train d'écrire une application de mise à jour et je ne peux pas impliquer de DLL dans le processus d'extraction depuis, je devrais également les mettre à jour .... c'est bien.Merci!
Niklas
27

Utilisez la bibliothèque DotNetZip à http://www.codeplex.com/DotNetZip

bibliothèque de classes et ensemble d'outils pour manipuler les fichiers zip. Utilisez VB, C # ou tout autre langage .NET pour créer, extraire ou mettre à jour facilement des fichiers zip ...

DotNetZip fonctionne sur les PC avec le .NET Framework complet et fonctionne également sur les appareils mobiles qui utilisent le .NET Compact Framework. Créez et lisez des fichiers zip en VB, C #, ou n'importe quel langage .NET, ou n'importe quel environnement de script ...

Si tout ce que vous voulez, c'est une meilleure classe DeflateStream ou GZipStream pour remplacer celle qui est intégrée dans le .NET BCL, DotNetZip l'a aussi. DeflateStream et GZipStream de DotNetZip sont disponibles dans un assemblage autonome, basé sur un port .NET de Zlib. Ces flux prennent en charge les niveaux de compression et offrent des performances bien meilleures que les classes intégrées. Il y a aussi un ZlibStream pour compléter l'ensemble (RFC 1950, 1951, 1952) ...

Sam Axe
la source
1
Hmmm ... Mais c'est une bibliothèque tierce!
Petteri
30
Comme vous êtes très attentif. Sauf si vous avez envie de passer plusieurs mois à implémenter votre propre lecteur de fichiers Zip, c'est votre meilleure option.
Sam Axe
Celui-ci est bien meilleur que SharpZipLib
Kugel
5
Vous me posez des questions sur une réponse vieille de près de 5 ans. Fais quelques recherches. Je suis sûr que vous trouverez une réponse.
Sam Axe
2
@PhilCooper C'est une très vieille question que je recommande d'utiliser le System.IO.Compression.ZipFile intégré. IIRC J'ai eu de très mauvaises expériences avec SharpZipLib dans le passé sur la base de mon expérience de production de milliers de zips à la volée.
Kugel
9
String ZipPath = @"c:\my\data.zip";
String extractPath = @"d:\\myunzips";
ZipFile.ExtractToDirectory(ZipPath, extractPath);

Pour utiliser la classe ZipFile, vous devez ajouter une référence à l'assembly System.IO.Compression.FileSystem dans votre projet

Mahadev Mane
la source
2

Les fichiers zip standard utilisent normalement l'algorithme de dégonflage.

Pour extraire des fichiers sans utiliser de bibliothèques tierces, utilisez DeflateStream. Vous aurez besoin d'un peu plus d'informations sur le format d'archive du fichier zip car Microsoft ne fournit que l'algorithme de compression.

Vous pouvez également essayer d'utiliser zipfldr.dll. Il s'agit de la bibliothèque de compression de Microsoft (dossiers compressés à partir du menu Envoyer vers). Il semble que ce soit une bibliothèque de com mais elle n'est pas documentée. Vous pourrez peut-être le faire fonctionner pour vous grâce à l'expérimentation.

Kenneth Cochran
la source
J'essaie la classe DeflateStream. Cette fois, j'obtiens System.IO.InvalidDataException: la longueur du bloc ne correspond pas à son complément ..
Petteri
Comme je l'ai dit ci-dessus, Microsoft n'a fourni que l'algorithme. Vous aurez également besoin d'informations sur le format d'archive zip. en.wikipedia.org/wiki/ZIP_(file_format) devrait vous aider à démarrer. Voir les références au bas de la page pour des liens vers des informations plus détaillées.
Kenneth Cochran
2
Je suis également tombé sur System.IO.Packaging.Package dans .NET 3.5. Il semble qu'il puisse faire l'affaire, mais ce n'est pas très intuitif.
Kenneth Cochran
2

Je l'utilise pour compresser ou décompresser plusieurs fichiers. Le truc Regex n'est pas requis, mais je l'utilise pour changer le timbre à date et supprimer les traits de soulignement indésirables. J'utilise la chaîne vide dans la chaîne Compress >> zipPath pour préfixer quelque chose à tous les fichiers si nécessaire. En outre, je commente généralement Compress () ou Decompress () en fonction de ce que je fais.

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
la source
Cela nécessite dot net 4.5 - juste une note comme l'ont noté ceux qui ont répondu avec ZipFile et j'utilise toujours 3.5.
Thronk
2

Cela le fera System.IO.Compression.ZipFile.ExtractToDirectory(ZipName, ExtractToPath)

Ilya Kochetov
la source
1

D' ici :

Les objets GZipStream compressés écrits dans un fichier avec une extension .gz peuvent être décompressés à l'aide de nombreux outils de compression courants; cependant, cette classe ne fournit pas intrinsèquement des fonctionnalités pour ajouter ou extraire des fichiers à partir d'archives .zip.

RedWolves
la source
1

Vous pouvez tout faire dans .NET 3.5 à l'aide de DeflateStream. La chose qui manque dans .NET 3.5 est la possibilité de traiter les sections d'en-tête de fichier utilisées pour organiser les fichiers zippés. PKWare a publié ces informations, que vous pouvez utiliser pour traiter le fichier zip après avoir créé les structures utilisées. Ce n'est pas particulièrement onéreux, et c'est une bonne pratique dans la construction d'outils sans utiliser de code tiers.

Ce n'est pas une réponse d'une seule ligne, mais c'est complètement faisable si vous êtes disposé et capable de prendre le temps vous-même. J'ai écrit une classe pour le faire en quelques heures et ce que j'ai obtenu c'est la possibilité de compresser et de décompresser des fichiers en utilisant .NET 3.5 uniquement.

Michael Blake
la source
0

J'ai découvert celui-ci (package Unzip sur NuGet) aujourd'hui, car j'ai rencontré un bogue dur dans DotNetZip, et j'ai réalisé qu'il n'y avait pas vraiment beaucoup de travail effectué sur DotNetZip au cours des deux dernières années.

Le paquet Unzip est maigre, et il a fait le travail pour moi - il n'avait pas le bug que DotNetZip avait. En outre, il s'agissait d'un fichier raisonnablement petit, s'appuyant sur le Microsoft BCL pour la décompression réelle. Je pouvais facilement faire les ajustements dont j'avais besoin (pour pouvoir suivre la progression pendant la décompression). Je le recommande.

Per Lundberg
la source
0

De Embed Ressources:

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

Jusqu'à présent, j'utilisais des processus cmd pour extraire un fichier .iso, le copier dans un chemin temporaire depuis le serveur et extrait sur une clé USB. Récemment, j'ai trouvé que cela fonctionnait parfaitement avec des .iso de moins de 10 Go. Pour une iso comme 29 Go, cette méthode est bloquée d'une manière ou d'une autre.

    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
la source
0

vous pouvez utiliser la ligne de commande Info-unzip cod.vous n'avez qu'à télécharger unzip.exe depuis le site officiel d'Info-unzip.

 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
la source