黄立柳

导航

 

前言:sevenzipsharp检查密码(包括检查压缩包的有效性)的函数是SevenZipExtractor.check(), sevenzipsharp调用的是7zip的动态链接库,而且不止是7zip,其它压缩软件测试密码这个功能耗时也很久(压缩包小可以忽略,密码错误的时候速度还行,密码正确的话,会把压缩包全部解压,耗时相当于解压一个文件的时间),除了360压缩比较快,至少快几百倍,但是找不到调用的方法,如果谁有更好的解决方案,麻烦提供一下。

原来的check方法4G大小的文件大概耗时

错误的密码:www.cr173.com用时:0.19秒
正确的密码:www.he11oworld.com用时:85.98秒

方案1:我的思路是既然检测一个压缩包的解压密码,没必要把所有的文件都检测一遍,取压缩包最小的加密文件去检测就行了,4G大小的文件大概耗时

错误的密码:www.cr173.com用时:0.19秒
正确的密码:www.he11oworld.com用时:26.18秒

方案2:同样是检查一个文件,检查第一个加密文件,,4G大小的文件大概耗时

错误的密码:www.cr173.com用时:0.12秒
正确的密码:www.he11oworld.com用时:0.10秒

发现方案二是最优的,一下是具体实现的代码

定义一个全局字段,用来存取压缩包内最小的文件索引和大小

private IDictionary<int, ulong> encryptionFileInfo = null;

初始化窗体时实例化

encryptionFileInfo = new Dictionary<int, ulong>();

获取压缩包信息时,保存最小文件的索引和大小

encryptionFileInfo.Clear();
foreach (ArchiveFileInfo item in extr.ArchiveFileData)
                {
                    if (item.Encrypted)
                    {
                        if (encryptionFileInfo.Count == 0)
                        {
                            encryptionFileInfo.Add(item.Index, item.Size);
                        }
                        ////只检测最小文件的实现方法
                        //else
                        //{
                        //    if (encryptionFileInfo.Values.ElementAt(0) > item.Size)
                        //    {
                        //        encryptionFileInfo.Clear();
                        //        encryptionFileInfo.Add(item.Index, item.Size);
                        //    }
                        //}
                    }
                }

实现优化函数,在SevenZipExtractor.cs单元添加函数如下函数

/// <summary>
        /// 检查压缩包密码
        /// </summary>
        /// <param name="minFileIndex">压缩包中加密文件索引最小的值</param>
        /// <returns></returns>
        public bool Check(int minFileIndex)
        {
            DisposedCheck();
            try
            {
                InitArchiveFileData(false);
                var archiveStream = GetArchiveStream(true);
                var openCallback = GetArchiveOpenCallback();
                if (!OpenArchive(archiveStream, openCallback))
                {
                    return false;
                }
                using (var aec = GetArchiveExtractCallback("", (int)_filesCount, null))
                {
                    try
                    {
                        uint[] u = new uint[1];
                        u[0] = uint.Parse(minFileIndex.ToString());
                        CheckedExecute(
                                                    _archive.Extract(u, 1, 1, aec),
                                                    SevenZipExtractionFailedException.DEFAULT_MESSAGE, aec);
                        //CheckedExecute(
                        //    _archive.Extract(null, UInt32.MaxValue, 1, aec),
                        //    SevenZipExtractionFailedException.DEFAULT_MESSAGE, aec);
                    }
                    finally
                    {
                        FreeArchiveExtractCallback(aec);
                    }
                }
            }
            catch (Exception)
            {
                return false;
            }
            finally
            {
                if (_archive != null)
                {
                    _archive.Close();
                }
                ((InStreamWrapper)_archiveStream).Dispose();
                _archiveStream = null;
                _opened = false;
            }
            return true;
        }

之后就是调用了,

using (SevenZipExtractor extr = new SevenZipExtractor(tbPackagePath.Text, Convert.ToString(item["Password"])))
                {
                    
                    if (extr.Check(index))
                    {
                        tbPassword.Text = Convert.ToString(item["Password"]);
                        memoEdit1.Text = memoEdit1.Text + "此为正确密码:" + Convert.ToString(item["Password"]) + "用时:" + (DateTime.Now - dtStartDetail).TotalMilliseconds.ToString() + "\r\n";
                        return;
                    }
                    memoEdit1.Text = memoEdit1.Text + "测试密码:" + Convert.ToString(item["Password"]) + "用时:" + (DateTime.Now - dtStartDetail).TotalMilliseconds.ToString() + "\r\n";                    
                }

 如果只用方案2可以把IDictionary<int, ulong>换成整型

posted on 2016-04-11 04:36  黄立柳  阅读(749)  评论(0编辑  收藏  举报