2012-08-16 75 views
10

我目前使用SharpZip api來處理我的zip文件條目。它適用於壓縮和解壓縮。雖然,我無法識別文件是否是zip文件。我需要知道是否有辦法檢測文件流是否可以解壓縮。最初我用過C#.net標識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) 
{ 

LZipStreamTester每次都變爲空,if語句失敗。我嘗試了/沒有緩衝區。有人可以提供任何見解,爲什麼?我知道我可以檢查文件擴展名。我需要比這更明確的東西。我也知道,zip有一個魔術#(PK東西),但它不能保證它總是會在那裏,因爲它不是格式的要求。

而且我也讀到了.NET 4.5具有天然的zip支持,所以我的項目可能遷移到的,而不是sharpzip但我仍然需要沒有看到類似CanDecompressEntry這裏的方法/參數:http://msdn.microsoft.com/en-us/library/3z72378a%28v=vs.110%29

我的最後一招將使用try catch並嘗試解壓縮該文件。

+0

我的問題的最簡單的形式是這樣的「在上面的代碼,爲什麼if語句返回false?」 – 2012-08-17 19:40:03

回答

5

這是需要處理未壓縮,PKZIP壓縮(sharpziplib)或GZip壓縮(內置.net)數據的組件的基類。也許比你需要的多一點,但應該讓你去。這是一個使用@ PhonicUK的建議來解析數據流頭部的例子。在小工廠方法中看到的派生類處理了PKZip和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

這很有幫助,但是從研究中我已經完成了PK文件頭或幻數,並不是確定文件是否爲zip的可靠方法。謝謝你。 – 2012-08-16 22:48:37

+1

雖然沒有問題,但是這來自一個系統,壓縮數據的來源得到很好的理解和控制。祝你好運! – dkackman 2012-08-16 22:52:18

+0

我將不得不對我們的文件系統進行審計。我相信一個PK幻數檢查,文件擴展名和嘗試解壓縮的混合就足夠了。我們最初希望避免使用try catch來確定文件是否是zip文件,但它必須位於此處。即使我們假設幻數上有一個zip,我們仍然需要嘗試catch來確定zip是否損壞。我希望我能代表你,但現在太白癡了。我們也重新修改了我們如何上傳文件以消除一些含糊之處。再次感謝。 – 2012-08-17 19:35:55

7

您可以:

  • 使用try-catch結構和嘗試讀取一個潛在的zip文件
  • 的結構解析文件頭,看它是否是一個zip文件

ZIP文件始終以0x04034b50作爲其前4個字節(http://en.wikipedia.org/wiki/Zip_(file_format)#File_headers

+0

維基百科和其他來源已經列出,幻數不是確定文件是否爲zip的好方法,因爲它不是zip文件格式所必需的。 另外,我們想避免嘗試捕捉,但這是目前的方法。 – 2012-08-16 22:45:27

+1

注:0x04034B50是小端,所以文件的第一個字節是0x50,第二個是0x4B等等... – vojta 2016-05-05 12:06:30

2

如果您正在爲Web編程,則可以檢查文件Content Type:application/z ip

9

查看https://stackoverflow.com/a/16587134/206730參考

檢查下面的鏈接:

icsharpcode-sharpziplib-validate-zip-file

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

ZIP文件總是與0x04034b50(4字節)開始
查看更多:http://en.wikipedia.org/wiki/Zip_(file_format)#File_headers

使用範例:

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

    }