解压缩具有特定扩展名的文件(不是.zip)

时间:2018-02-14 15:35:22

标签: c# archive unzip compression deflate

如何使用以下文件特征解压缩下载的压缩文件(使用Deflate方法压缩,ANSI编码)

  • 动态扩展(例如.23U或.23M)
  • 使用Deflate方法和ANSI编码
  • 进行压缩
  • 可以通过7-Zip作为存档打开,但在提取打开时仍然无法读取

以下技术要点

  • 以任何方式使用DeflateStream都无法正常工作
  • 使用GZipStream适用于.gz
  • 经常推荐使用DotNetZip libray但是太重了,无法参考项目(并没有真正记录)

在另一个c ++项目中(我实际上需要模仿C#中的行为),使用 dunzip.dll 库并导致可读字符。 我们可以在网上看到C#存在 dunzip32.dll libray,但是没有关于如何使用它的文档。

编辑:

以下是我从压缩文件中获取的字节数组的前100个字节(十进制):

80 75 3 4 20 0 8 0 8 0 67 75 79 76 0 0 0 0 0 0 0 0 0 0 0 0 12 0 0 0 50 50 67 67 48 48 48 49 46 50 51 85 204 189 117 88 85 251 215 238 77 9 2 210 221 157 210 221 221 221 139 142 69 119 119 119 119 119 119 119 135 32 8 136 10 38 2 10 38 138 138 29 32 234 59 231 210 189 55 107 242 187 246 251 158 115 158 231 60 239 255

这是一个报告,我得到 100个第一个字节的六进制

0000-0010:  50 4b 03 04-14 00 08 00-08 00 60 4b-47 4c 00 00  PK...... ..`KGL..
0000-0020:  00 00 00 00-00 00 00 00-00 00 0c 00-00 00 32 32  ........ ......22
0000-0030:  43 43 30 30-30 31 2e 32-33 55 cc bd-75 58 55 fb  CC0001.2 3U..uXU.
0000-0040:  d7 ee 4d 09-02 d2 dd 9d-d2 dd dd dd-8b 8e 45 77  ..M..... ......Ew
0000-0050:  77 77 77 77-77 77 87 20-08 88 0a 26-02 0a 26 8a  wwwwww.. ...&..&.
0000-0060:  8a 1d 20 ea-3b e7 d2 bd-37 6b f2 bb-f6 fb 9e 73  ....;... 7k.....s
0000-0064:  9e e7 3c ef                                      ..<.

以50 4b 03 04开头的事实意味着它是基于zip的格式:File signatures information 然后,将其视为zip文件,我尝试使用msdn示例中的简单方法解压缩数据,在一种情况下使用MemoryStream,在另一种情况下使用FileStream。

public static string UnzipString3(byte[] byteArrayCompressedContent)
{
    using (var outputStream = new MemoryStream())
    {
        using (var compressStream = new MemoryStream(byteArrayCompressedContent))
        {
            using (var deflateStream = new DeflateStream(compressStream, CompressionMode.Decompress))
            {
                deflateStream.CopyTo(outputStream);
            }
        }
        return Encoding.UTF8.GetString(outputStream.ToArray());
    }
}


public void UnzipProperZipFile()
{
        try
        {
            using (var outputStream = new MemoryStream())
            {
                FileInfo fileInfo = new FileInfo("NormalZip.zip");
                FileStream fileStream = fileInfo.OpenRead();
                fileStream.Position = 2;
                using (var deflateStream = new DeflateStream(fileStream, CompressionMode.Decompress))
                {
                    deflateStream.CopyTo(outputStream);
                }
                string res = Encoding.UTF8.GetString(outputStream.ToArray());
            }
        }
        catch (Exception e)
        {
            Console.WriteLine("errorlole");
        }
}

在这两种情况下,它都会给出“块长度与其补充”错误。但是,它是Microsoft推荐的方法,应该以这种方式工作。 我意识到,如果我消耗前两个字节,它不会给出错误,而是会导致一个空字符串......

编辑:

我显然面临着与“正确”的zip文件相同的问题(即使其他人使用相同的算法也取得了成功),所以我将尝试使用外部解压缩库。

修改

它正在使用LasseVågsætherKarlsen建议的Class ZipArchive,他的代码在解压缩后获取数据的工作正常。 现在剩下的就是能够获得可理解的数据。我实际上对数据知之甚少,除了:

  • 记事本告诉我它是ANSI编码的

当我在提取文件后在MemoryStream中传输数据时,我尝试在所有使用的编码中获取它;

entryStream.CopyTo(memoryStream);
string laChaineUTF8 = Encoding.UTF8.GetString(memoryStream.ToArray());
string laChaineDefault = Encoding.Default.GetString(memoryStream.ToArray());
string laChaineUnicode = Encoding.Unicode.GetString(memoryStream.ToArray());
string laChaineASCII = Encoding.ASCII.GetString(memoryStream.ToArray());
string laChaineBigEndianUnicode = Encoding.BigEndianUnicode.GetString(memoryStream.ToArray());
string laChaineUTF7 = Encoding.UTF7.GetString(memoryStream.ToArray());
string laChaineUTF32 = Encoding.UTF32.GetString(memoryStream.ToArray());

他们都没有提供可理解的人物链。

1 个答案:

答案 0 :(得分:2)

问题在于.ZIP文件不仅仅是简单的数据泄露。有目录结构,校验和,文件元数据等等。

您需要使用知道此结构的类。除非文件使用一些更高级的东西,例如加密和跨越档案,否则.NET ZipArchive类可能会起到作用。

这是一个简单的程序,它从zip存档中提取文本文件的内容。你必须根据自己的需要进行调整:

using (var file = File.Open(@"D:\Temp\Temp.zip", FileMode.Open))
using (var archive = new ZipArchive(file))
{
    var entry = archive.GetEntry("ttt/README.md");
    using (var entryStream = entry.Open())
    using (var memory = new MemoryStream())
    {
        entryStream.CopyTo(memory);
        Console.WriteLine(Encoding.UTF8.GetString(memory.ToArray()));
    }
}