Descomprima archivos mediante programación en .net

221

Estoy tratando de descomprimir programáticamente un archivo comprimido.

Intenté usar la System.IO.Compression.GZipStreamclase en .NET, pero cuando se ejecuta mi aplicación (en realidad una prueba unitaria) obtengo esta excepción:

System.IO.InvalidDataException: el número mágico en el encabezado GZip no es correcto. Asegúrate de pasar una transmisión GZip

Ahora me doy cuenta de que un .ziparchivo no es lo mismo que un .gzarchivo, y que GZipno es lo mismo que Zip.

Sin embargo, dado que puedo extraer el archivo haciendo doble clic manualmente en el archivo comprimido y luego haciendo clic en el botón "Extraer todos los archivos", creo que también debería haber una forma de hacerlo en el código.

Por lo tanto, he tratado de usar Process.Start()con la ruta al archivo comprimido como entrada. Esto hace que mi aplicación abra una ventana que muestra el contenido del archivo comprimido. Está bien, pero la aplicación se instalará en un servidor sin ninguno para hacer clic en el botón "Extraer todos los archivos".

Entonces, ¿cómo hago para que mi aplicación extraiga los archivos en los archivos comprimidos?

¿O hay otra forma de hacerlo? Prefiero hacerlo en código, sin descargar ninguna biblioteca o aplicación de terceros; al departamento de seguridad no le gusta mucho eso ...

Petteri
fuente
12
¿Su departamento de seguridad está más feliz con usted escribiendo su propio código para algo que usando una biblioteca que ha sido depurada y examinada por muchos ojos? Puede usar una biblioteca Y "hacerlo en código" (obtenga la fuente y compílelo usted mismo), pero veo que reinventar la rueda es un problema mayor que cualquier problema de seguridad provocado por el uso de una biblioteca probada y verdadera.
Jared Updike
10
@Jared - Cuando la gerencia tiene una idea en la cabeza ...
Steven Evers
44
Hay menos riesgo para el departamento de seguridad si obtiene un producto de terceros. Sólo tiene que descargar DotNetZip y cambiarle el nombre "[insertar nombre de la empresa] .ziplibrary.dll"
Simon

Respuestas:

59

Hemos utilizado SharpZipLib con éxito en muchos proyectos. Sé que es una herramienta de terceros, pero el código fuente está incluido y podría proporcionar alguna información si decide reinventar la rueda aquí.

Chris Conway
fuente
3
Intenté usar SharpZipLib y funcionó bien. Supongo que tendré que ver si la prohibición de libs y apss de terceros es una regla estricta o más una guía.
Petteri
10
No sé acerca de su empresa, pero mi experiencia siempre ha sido que es posible obtener una excepción a ese tipo de regla si escribe una descripción del caso de negocios de por qué desea la excepción. Señale los ahorros en costos v. Bricolaje, así como el hecho de que se puede examinar la fuente. Como alternativa, a menudo puede obtener permiso para usar la fuente incluso si no le permiten usar el dll, luego simplemente compílelo usted mismo (o al menos las partes que realmente necesita usar ...).
RolandTumble
No tiene que usar bibliotecas externas para descomprimir archivos zip, puede usar Shell32 de System32. Consulte stackoverflow.com/a/43066281/948694
arturn
490

Con .NET 4.5 ahora puede descomprimir archivos usando .NET framework:

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

El código anterior se tomó directamente de la documentación de Microsoft: http://msdn.microsoft.com/en-us/library/ms404280(v=vs.110).aspx

ZipFileestá contenido en la asamblea System.IO.Compression.FileSystem. (Gracias nateirvin ... ver comentario más abajo)

bsara
fuente
118
Por cierto, ZipFileestá contenido en el conjunto System.IO.Compression.FileSystem.
nateirvin
73
Lo que significa que debe agregar una referencia de DLL al ensamblado de marco System.IO.Compression.FileSystem.dll.
Chris Schiffhauer
¿Qué pasa con los archivos .rar? el código anterior no puede extraer archivos .rar.
Raghu
1
Intenté esto en mi API web principal de asp.net, decía bien la primera entrada, pero en la segunda entrada siempre da error A local file header is corrupt. ¿Alguna idea sobre esto?
SoftSan
Lo mismo con @SoftSan. También recibí ese error. ¿Qué hacer?
Rico
101

Para .Net 4.5+

No siempre se desea escribir el archivo sin comprimir en el disco. Como desarrollador de ASP.Net, tendría que jugar con los permisos para otorgar derechos para que mi aplicación escriba en el sistema de archivos. Al trabajar con secuencias en la memoria, puedo evitar todo eso y leer los archivos directamente:

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

Alternativamente, aún puede escribir el archivo descomprimido en el disco llamando a ExtractToFile():

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

Para usar la ZipArchiveclase, deberá agregar una referencia al System.IO.Compressionespacio de nombres y para System.IO.Compression.FileSystem.

Señor épico
fuente
8
¿Realmente tomó MSFT hasta 4.5+ para agregar un descompresor nativo?
John Peters
2
@JohnPeters GZipStream se agregó nuevamente en .Net 2.0 ( msdn.microsoft.com/en-us/library/… ). Sin embargo, no facilitó el trabajo con varios archivos en un archivo en la memoria. El nuevo ZipArchiveobjeto se ajusta muy bien.
Mister Epic
1
Esta es una alternativa particularmente buena porque permite descomprimir sin usar el sistema de archivos (en mi caso estoy trabajando con recursos integrados), y tampoco es una extensión de terceros.
ANeves
1
¿Por qué debería usar un foreachbucle ExtractToFilecuando solo puedo usar? ZipFile.ExtractToDirectory(inputFile, outputDir);¿Cuál es la ventaja del primer método?
The Fluffy Robot
1
en .NET 4.6.1 no puedo obtener 'ZipArchive' de 'System.IO.Compression.FileSystem', ¿alguna idea?
Ravi Anand
55

Gratis y sin archivos DLL externos. Todo está en un archivo CS. Una descarga es solo el archivo CS, otra descarga es un ejemplo muy fácil de entender. Lo probé hoy y no puedo creer lo simple que fue la configuración. Funcionó en el primer intento, sin errores, sin nada.

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

Lukas
fuente
Habló demasiado pronto! Quiero inflar los archivos de una secuencia de descarga http al instante. Esto no funciona ya que está utilizando operaciones de Búsqueda en la transmisión :( Bueno, gracias al código fuente, ahora puedo escribir mi propio ZipStream ...
oyophant
la mejor solución a mi problema, ya que estoy escribiendo una aplicación de actualización y no puedo involucrar ninguna DLL en el proceso de extracción, desde entonces también tendría que actualizarlas ... esto es bueno. ¡Gracias!
Niklas
27

Use la biblioteca DotNetZip en http://www.codeplex.com/DotNetZip

biblioteca de clases y conjunto de herramientas para manipular archivos zip. Use VB, C # o cualquier lenguaje .NET para crear, extraer o actualizar fácilmente archivos zip ...

DotNetZip funciona en PC con .NET Framework completo, y también se ejecuta en dispositivos móviles que usan .NET Compact Framework. Cree y lea archivos zip en VB, C #, o cualquier lenguaje .NET, o cualquier entorno de secuencias de comandos ...

Si todo lo que desea es una mejor clase DeflateStream o GZipStream para reemplazar la que está integrada en .NET BCL, DotNetZip también lo tiene. DeflateStream y GZipStream de DotNetZip están disponibles en un ensamblaje independiente, basado en un puerto .NET de Zlib. Estas transmisiones admiten niveles de compresión y ofrecen un rendimiento mucho mejor que las clases integradas. También hay un ZlibStream para completar el conjunto (RFC 1950, 1951, 1952) ...

Sam Axe
fuente
1
Hmmm ... ¡Pero esa es una biblioteca de terceros!
Petteri
30
Qué observador de tu parte. A menos que tenga ganas de pasar varios meses implementando su propio lector de archivos Zip, es su mejor opción.
Sam Axe
Este es mucho mejor que SharpZipLib
Kugel
55
Me estás haciendo preguntas sobre una respuesta que tiene casi 5 años. Investiga un poco. Estoy seguro de que encontrarás una respuesta.
Sam Axe
2
@PhilCooper Esta es una pregunta muy antigua que recomiendo usar el System.IO.Compression.ZipFile incorporado. IIRC Tuve experiencias realmente malas con SharpZipLib en el pasado debido a mi experiencia de producir miles de cremalleras sobre la marcha.
Kugel
9
String ZipPath = @"c:\my\data.zip";
String extractPath = @"d:\\myunzips";
ZipFile.ExtractToDirectory(ZipPath, extractPath);

Para usar la clase ZipFile, debe agregar una referencia al ensamblado System.IO.Compression.FileSystem en su proyecto

Mahadev Mane
fuente
2

Los archivos zip estándar normalmente usan el algoritmo de desinflado.

Para extraer archivos sin usar bibliotecas de terceros, use DeflateStream. Necesitará un poco más de información sobre el formato de archivo comprimido ya que Microsoft solo proporciona el algoritmo de compresión.

También puede intentar usar zipfldr.dll. Es la biblioteca de compresión de Microsoft (carpetas comprimidas del menú Enviar a). Parece ser una biblioteca de comunicaciones, pero no está documentada. Puede lograr que funcione para usted a través de la experimentación.

Kenneth Cochran
fuente
Estoy probando la clase DeflateStream. Esta vez me sale System.IO.InvalidDataException: Longitud de bloque no coincide con su complemento ..
Petteri
Como dije anteriormente, Microsoft solo proporcionó el algoritmo. También necesitará información sobre el formato de archivo zip. en.wikipedia.org/wiki/ZIP_(file_format) debería ayudarlo a comenzar. Consulte las referencias en la parte inferior de la página para obtener enlaces a información más detallada.
Kenneth Cochran
2
También me topé con System.IO.Packaging.Package en .NET 3.5. Parece que puede hacer el truco, aunque no es muy intuitivo.
Kenneth Cochran
2

Lo uso para comprimir o descomprimir múltiples archivos. El material Regex no es obligatorio, pero lo uso para cambiar el sello de fecha y eliminar los guiones bajos no deseados. Uso la cadena vacía en la cadena Compress >> zipPath para anteponer algo a todos los archivos si es necesario. Además, generalmente comento Compress () o Decompress () en función de lo que estoy haciendo.

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
fuente
Esto requiere dot net 4.5, solo una nota como notaron otros que respondieron con ZipFile y todavía estoy usando 3.5.
Thronk
2

Esto lo hará System.IO.Compression.ZipFile.ExtractToDirectory(ZipName, ExtractToPath)

Ilya Kochetov
fuente
1

Desde aquí :

Los objetos comprimidos de GZipStream escritos en un archivo con una extensión de .gz pueden descomprimirse utilizando muchas herramientas de compresión comunes; sin embargo, esta clase no proporciona una funcionalidad inherente para agregar o extraer archivos de archivos .zip.

Lobos rojos
fuente
1

Puede hacerlo todo dentro de .NET 3.5 usando DeflateStream. Lo que falta en .NET 3.5 es la capacidad de procesar las secciones de encabezado de archivo que se utilizan para organizar los archivos comprimidos. PKWare ha publicado esta información, que puede utilizar para procesar el archivo zip después de crear las estructuras que se utilizan. No es particularmente oneroso, y es una buena práctica en la construcción de herramientas sin usar código de terceros.

No es una respuesta de una línea, pero es completamente factible si está dispuesto y puede tomarse el tiempo usted mismo. Escribí una clase para hacer esto en un par de horas y lo que obtuve de eso es la capacidad de comprimir y descomprimir archivos usando .NET 3.5 solo.

Michael Blake
fuente
0

Me enteré de este (Descomprimir paquete en NuGet) hoy, ya que me encontré con un error grave en DotNetZip, y me di cuenta de que realmente no se ha hecho tanto trabajo en DotNetZip en los últimos dos años.

El paquete Unzip es sencillo, e hizo el trabajo por mí, no tenía el error que tenía DotNetZip. Además, era un archivo razonablemente pequeño, que confiaba en el BCL de Microsoft para la descompresión real. Podía hacer fácilmente los ajustes que necesitaba (para poder realizar un seguimiento del progreso mientras se descomprime). Lo recomiendo.

Por Lundberg
fuente
0

De recursos de inserción:

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

Hasta ahora, estaba usando procesos cmd para extraer un archivo .iso, copiarlo en una ruta temporal desde el servidor y extraerlo en un dispositivo USB. Recientemente descubrí que esto funciona perfectamente con .iso's que son menos de 10Gb. Para una iso como 29 Gb, este método se atasca de alguna manera.

    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
fuente
0

puede usar la línea de comandos de Info-descomprimir cod. solo necesita descargar unzip.exe del sitio web oficial de Info-descomprimir.

 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
fuente