2012-08-16 5 views
10

Attualmente sto usando l'API SharpZip per gestire le mie voci del file zip. Funziona splendidamente per zippare e decomprimere. Tuttavia, sto riscontrando problemi nell'individuare se un file è un file zip o meno. Devo sapere se esiste un modo per rilevare se un flusso di file può essere decompresso. Inizialmente utilizzavoC# .net identifica il file zip

Il LZipStreamTester diventa null ogni volta e l'istruzione if fallisce. L'ho provato con/senza un buffer. Qualcuno può dare qualche idea sul perché? Sono consapevole che posso controllare l'estensione del file. Ho bisogno di qualcosa che sia più definitivo di così. Sono anche consapevole che zip ha un numero magico (PK qualcosa), ma non è una garanzia che sarà sempre lì perché non è un requisito del formato.

Inoltre ho letto di .NET 4.5 con supporto nativo zip quindi il mio progetto può migrare verso che invece di sharpzip, ma ho ancora bisogno di non vedere un metodo/param simile a CanDecompressEntry qui: http://msdn.microsoft.com/en-us/library/3z72378a%28v=vs.110%29

mio ultimo ricorso sarà utilizzare un try catch e tentare di decomprimere il file.

+0

La forma più semplice della mia domanda è questa "Nel codice di cui sopra, perché l'istruzione if return false?" –

risposta

5

Questa è una classe base per un componente che deve gestire dati non compressi, PKZIP compresso (sharpziplib) o GZip compresso (incorporato in .net). Forse un po 'più del necessario, ma dovresti farti andare. Questo è un esempio dell'utilizzo del suggerimento di @ PhonicUK per analizzare l'intestazione del flusso di dati. Le classi derivate che vedi nella piccola factory mathod hanno gestito le specifiche della decompressione PKZip e 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

Questo è utile ma dalla ricerca ho fatto l'intestazione del file PK o il numero magico non è un modo affidabile per determinare se un file è zip. Grazie comunque. –

+1

Non ho avuto problemi con questo, ma questo è da un sistema in cui le fonti dei dati compressi sono ben compresi e controllati. In bocca al lupo! – dkackman

+0

Ho intenzione di fare un controllo sul nostro file system per essere sicuro. Credo che il mix di un controllo del numero magico PK, l'estensione del file e il tentativo di decomprimere sia sufficiente. Inizialmente, volevamo evitare di utilizzare un try catch per determinare se il file era un file zip ma deve essere presente. Anche se ipotizziamo un numero magico su zip, dobbiamo ancora provare a catturare per determinare se lo zip è corrotto. Vorrei poterti replicare ma troppo noob adesso. Abbiamo anche rielaborato il modo in cui caricheremo i file per rimuovere alcune delle ambiguità. Grazie ancora. –

7

È possibile:

  • utilizzare una struttura try-catch e provare a leggere la struttura di un potenziale file zip
  • analizzare l'intestazione del file per vedere se si tratta di un file zip

file ZIP iniziano sempre con 0x04034b50 come i suoi primi 4 byte (http://en.wikipedia.org/wiki/Zip_(file_format)#File_headers)

+0

Wikipedia e altre fonti hanno elencato che il numero magico non è un buon modo per determinare se un file è uno zip perché non è richiesto per il formato file di un file zip. In alternativa, vorremmo evitare di provare a catturare, ma questo è il metodo attuale. –

+1

Nota: 0x04034B50 è little endian, quindi il primo byte del file è 0x50, il secondo è 0x4B e così via ... – vojta

2

Se si sta programmando per il Web, è possibile controllare il tipo di file contenuti: application/z ip

9

View https://stackoverflow.com/a/16587134/206730 riferimento

Controllare i link qui sotto:

icsharpcode-sharpziplib-validate-zip-file

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

file ZIP iniziano sempre con 0x04034b50 (4 bytes)
Vedi di più: http://en.wikipedia.org/wiki/Zip_(file_format)#File_headers

utilizzo Esempio:

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

    }