2012-08-16 32 views
10

Actualmente estoy usando la api de SharpZip para manejar mis entradas de archivo zip. Funciona espléndido para comprimir y descomprimir. Sin embargo, tengo problemas para identificar si un archivo es zip o no. Necesito saber si hay una manera de detectar si una secuencia de archivo se puede descomprimir. Originalmente utilicéC# .net identifique el archivo zip

FileStream lFileStreamIn = File.OpenRead(mSourceFile); 
lZipFile = new ZipFile(lFileStreamIn); 
ZipInputStream lZipStreamTester = new ZipInputStream(lFileStreamIn, mBufferSize);// not working 
lZipStreamTester.Read(lBuffer, 0, 0); 
if (lZipStreamTester.CanDecompressEntry) 
{ 

El LZipStreamTester se vuelve nulo cada vez y la instrucción if falla. Lo intenté con/sin un buffer. ¿Alguien puede dar alguna idea de por qué? Soy consciente de que puedo verificar la extensión del archivo. Necesito algo que sea más definitivo que eso. También soy consciente de que zip tiene un # mágico (PK algo), pero no es una garantía de que siempre estará allí porque no es un requisito del formato.

También leí sobre .NET 4.5 con soporte nativo postal así que mi proyecto puede migrar a que en lugar de sharpzip pero todavía necesitan no vio un método/param similar a CanDecompressEntry aquí: http://msdn.microsoft.com/en-us/library/3z72378a%28v=vs.110%29

Mi último recurso será utilizar una captura de prueba e intentar un descomprimir en el archivo.

+0

La forma más simple de mi pregunta es la siguiente "En el código anterior, ¿por qué la sentencia if return false?" –

Respuesta

5

Esta es una clase base para un componente que necesita manejar datos que no están comprimidos, PKZIP comprimido (sharpziplib) o GZip comprimido (incorporado en .net). Tal vez un poco más de lo que necesita, pero debería hacerlo funcionar. Este es un ejemplo del uso de la sugerencia de @ PhonicUK para analizar el encabezado de la secuencia de datos. Las clases derivadas que ves en la pequeña fábrica de mathod manejaron los detalles de la descompresión de PKZip y GZip.

abstract class Expander 
{ 
    private const int ZIP_LEAD_BYTES = 0x04034b50; 
    private const ushort GZIP_LEAD_BYTES = 0x8b1f; 

    public abstract MemoryStream Expand(Stream stream); 

    internal static bool IsPkZipCompressedData(byte[] data) 
    { 
     Debug.Assert(data != null && data.Length >= 4); 
     // if the first 4 bytes of the array are the ZIP signature then it is compressed data 
     return (BitConverter.ToInt32(data, 0) == ZIP_LEAD_BYTES); 
    } 

    internal static bool IsGZipCompressedData(byte[] data) 
    { 
     Debug.Assert(data != null && data.Length >= 2); 
     // if the first 2 bytes of the array are theG ZIP signature then it is compressed data; 
     return (BitConverter.ToUInt16(data, 0) == GZIP_LEAD_BYTES); 
    } 

    public static bool IsCompressedData(byte[] data) 
    { 
     return IsPkZipCompressedData(data) || IsGZipCompressedData(data); 
    } 

    public static Expander GetExpander(Stream stream) 
    { 
     Debug.Assert(stream != null); 
     Debug.Assert(stream.CanSeek); 
     stream.Seek(0, 0); 

     try 
     { 
      byte[] bytes = new byte[4]; 

      stream.Read(bytes, 0, 4); 

      if (IsGZipCompressedData(bytes)) 
       return new GZipExpander(); 

      if (IsPkZipCompressedData(bytes)) 
       return new ZipExpander(); 

      return new NullExpander(); 
     } 
     finally 
     { 
      stream.Seek(0, 0); // set the stream back to the begining 
     } 
    } 
} 
+0

Esto es útil, pero a partir de la investigación que he realizado, el encabezado del archivo PK o el número mágico no es una forma confiable de determinar si un archivo es zip. Gracias de cualquier forma. –

+1

No he tenido problemas con eso, pero esto es de un sistema donde las fuentes de los datos comprimidos son bien entendidos y controlados. ¡Buena suerte! – dkackman

+0

Voy a tener que hacer una auditoría en nuestro sistema de archivos para estar seguro. Creo que la combinación de un control de número mágico de PK, extensión de archivo y try catch on unzip será suficiente. Originalmente queríamos evitar usar un try catch para determinar si el archivo era zip pero tiene que estar ahí. Incluso si asumimos un número mágico con zip, aún tenemos que intentar capturar para determinar si el zip está dañado. Desearía poder representarte pero también novato en este momento. También hemos modificado la forma en que cargaremos los archivos para eliminar parte de la ambigüedad. Gracias de nuevo. –

7

Puede:

  • utilizar una estructura try-catch y tratar de leer la estructura de un archivo de potencial postal
  • analizar la cabecera de archivo para ver si se trata de un archivo zip

archivos ZIP siempre comienzan con 0x04034b50 como sus primeros 4 bytes (http://en.wikipedia.org/wiki/Zip_(file_format)#File_headers)

+0

Wikipedia y otras fuentes han enumerado que el número mágico no es una buena manera de determinar si un archivo es un archivo comprimido porque no es necesario para el formato de archivo de un archivo comprimido. Como alternativa, nos gustaría evitar intentar capturar pero ese es el método actual. –

+1

Nota: 0x04034B50 es poco endian, por lo que el primer byte del archivo es 0x50, el segundo byte es 0x4B y así sucesivamente ... – vojta

2

Si está programando para la web, puede comprobar el tipo de archivo de contenido: aplicación/z ip

9

Ver https://stackoverflow.com/a/16587134/206730 referencia

Comprobar los enlaces siguientes:

icsharpcode-sharpziplib-validate-zip-file

How-to-check-if-a-file-is-compressed-in-c#

archivos ZIP siempre comienzan con 0x04034b50 (4 bytes)
Ver más: http://en.wikipedia.org/wiki/Zip_(file_format)#File_headers

Ejemplo de uso:

 bool isPKZip = IOHelper.CheckSignature(pkg, 4, IOHelper.SignatureZip); 
     Assert.IsTrue(isPKZip, "Not ZIP the package : " + pkg); 

// http://blog.somecreativity.com/2008/04/08/how-to-check-if-a-file-is-compressed-in-c/ 
    public static partial class IOHelper 
    { 
     public const string SignatureGzip = "1F-8B-08"; 
     public const string SignatureZip = "50-4B-03-04"; 

     public static bool CheckSignature(string filepath, int signatureSize, string expectedSignature) 
     { 
      if (String.IsNullOrEmpty(filepath)) throw new ArgumentException("Must specify a filepath"); 
      if (String.IsNullOrEmpty(expectedSignature)) throw new ArgumentException("Must specify a value for the expected file signature"); 
      using (FileStream fs = new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 
      { 
       if (fs.Length < signatureSize) 
        return false; 
       byte[] signature = new byte[signatureSize]; 
       int bytesRequired = signatureSize; 
       int index = 0; 
       while (bytesRequired > 0) 
       { 
        int bytesRead = fs.Read(signature, index, bytesRequired); 
        bytesRequired -= bytesRead; 
        index += bytesRead; 
       } 
       string actualSignature = BitConverter.ToString(signature); 
       if (actualSignature == expectedSignature) return true; 
       return false; 
      } 
     } 

    } 
Cuestiones relacionadas