使用Ionic.Zip在C#中解压缩包含额外数据的存档

问题描述

我需要从包含额外数据的zip文件提取数据。

当我使用7-zip打开它时,它可以正常工作,但是属性中存在警告-“有效负载数据结束后有一些数据”

但是当我尝试使用DotNetZip解压缩它时,会给我一个错误

using (var zip = ZipFile.Read("test.ef4"))
            {
                foreach (var zipEntry in zip)
                {
                    Console.WriteLine(zipEntry.FileName);
                    var MemoryStream = new MemoryStream();
                    zipEntry.OpenReader().copyTo(MemoryStream);
                    File.WriteallBytes(zipEntry.FileName,MemoryStream.ToArray());
                }
            }

Exception:
Unhandled Exception: Ionic.Zip.ZipException: Cannot read that as a ZipFile 
---> Ionic.Zip.BadReadException:   Bad signature (0x0C000001) at position 0x00000060

我该如何忽略此异常并像7-zip一样从文件中解压缩?


要重现它,可以使用Windows cmd.exe创建存档

使用一些随机数据创建archive.zip和exTradata.txt。然后执行以下命令-

   copy /b archive.zip+exTradata.txt

解决方法

我找到了适合我的解决方案:

在我的情况下,所有zip文件都具有\ x50 \ x4b \ x01 \ x02或\ x50 \ x4b \ x03 \ x04之类的标头。 (前\ x50 \ x4b始终相同。后半部分可以不同)

所以我写了一个代码,该代码在字节内找到我的ZIP文件的偏移量。文件的页脚对于C#中的任何ziplib都不重要

class Program
{
    static void Main(string[] args)
    {
        var content = File.ReadAllBytes("qv.zip");
        content = content.Skip(FirstPattern(content)).ToArray();

        using (var zip = ZipFile.Read(new MemoryStream(content),new ReadOptions() {}))
        {
            foreach (var zipEntry in zip)
            {
                Console.WriteLine(zipEntry.FileName);
                var MemoryStream = new MemoryStream();
                zipEntry.OpenReader().CopyTo(MemoryStream);
                File.WriteAllBytes(zipEntry.FileName,MemoryStream.ToArray());
            }
        }


    }

    private static int FirstPattern(byte[] bytes)
    {
        var header = StringToByteArray("504b0304"); // In my case all broken zip-files had 0304 ending

        for (int i = 0; i < bytes.Length - header.Length; i++)
        {
            var j = 0;
            while(j < header.Length && bytes[i + j] == header[j])
            {
                j++;
            }

            if(j == header.Length
                return i;
        }

        return -1;
    }

    public static byte[] StringToByteArray(string hex)
    {
        int numberChars = hex.Length;
        byte[] bytes = new byte[numberChars / 2];
        for (int i = 0; i < numberChars; i += 2)
            bytes[i / 2] = Convert.ToByte(hex.Substring(i,2),16);
        return bytes;
    }
}