有关7z的代码阅读

来源:互联网 发布:起凡平台登录网络错误 编辑:程序博客网 时间:2024/04/30 15:13

原因:

由于服务器存在大数据量日志.日志使用tgz格式压缩的。数据量降低到了原来的1/20差不多。如果处理需要进行解压,查询就太麻烦了。而且需要的空间一下子增加了好多。然后就想要做一个小程序,支持对压缩文件直接进行处理。

首先就想到了对现有的开源压缩解压库。没找到线程的,就用7z把。反正也比较容易转成库。


代码的编译:
我用的是vs2008 sp1。 在通过取消7zCrcOpt.asm和AesOpt.asm的ml -omf参数后,编译就OK了。
使用vs2008的时候会提示 xmm1, xmm2, xmm3找不到的问题


编译CPP/7Zip/Bundles/Format7ZF生成 DLL
编译CPP/7Zip/UI/COnsole生成 exe
具体各个文件夹的作用可以参考readme.txt


功能测试:
把编译的7z.dll 放在7z.exe相同路径下。进行测试。


开始代码阅读前,可以大体上了解一下工具的功能。由于我主要是想要使用Lib的压缩解压功能,所以使用以下命令:


7z.exe [command] [switch] [archiveFileName] [fileName fileName]


7z.exe a -ttar 1.tar 1.txt 2.txt
7z.exe a -tgzip 1.tar.gz 1.tar
7z.exe e -tgzip 1.tar.gz
7z.exe e -ttar 1.tar


代码历程:


首先是解析参数


CArchiveCommandLineOptions options; // 可以看看具体的结构体。就知道所有的相关压缩解压设定都会在该结构内体现


parser.Parse1(commandStrings, options); // 解析了输入参数。主要是解析switch参数


parser.Parse2(options); // 生成options了。参数解析完毕。后续要进行具体操作了


  CCodecs *codecs = new CCodecs; // 加载编码器
  CMyComPtr<
    #ifdef EXTERNAL_CODECS
    ICompressCodecsInfo
    #else
    IUnknown
    #endif
    > compressCodecsInfo = codecs;
  HRESULT result = codecs->Load();

CIntVector formatIndices;
   if (!codecs->FindFormatForArchiveType(options.ArcType, formatIndices))// 通过-t提供的类型获取操作类型
    throw kUnsupportedArcTypeMessage;

后续根据刚才的command参数觉得执行入口


  if (options.Command.CommandType == NCommandType::kInfo)
  {
  }
  else if (options.Command.CommandType == NCommandType::kBenchmark)
  {
  }
  else if (isExtractGroupCommand || options.Command.CommandType == NCommandType::kList)// 解压缩在这里
  {
  }
  else if (options.Command.IsFromUpdateGroup()) // 压缩在这里
  {
  }
  else
    PrintHelpAndExit(stdStream);

准备回调,还有具体解压缩参数


CExtractCallbackConsole *ecs = new CExtractCallbackConsole;// 这个是回调
CExtractOptions eo; // 这个是参数


后面就是解压缩了


      HRESULT result = DecompressArchives(
          codecs,
          formatIndices,
          options.ArchivePathsSorted,
          options.ArchivePathsFullSorted,
          options.WildcardCensor.Pairs.Front().Head,
          eo, &openCallback, ecs, errorMessage, stat);
 
过程中多次调用回调返回信息。然后就结束了。主体流程完成。


后面深入体会一下解压流程


    HRESULT result = archiveLink.Open2(codecs, formatIndices2, options.StdInMode, NULL, arcPath, openCallback);// 打开压缩文件。该函数把每种格式都打开了一个对应的文件流或者内存流。
    if (result == E_ABORT)
      return result;
 
// 在这个函数内部,我们看到了压缩解压实际代码的身影
(1) CArchiveLink::Open2 -> CArchiveLink::Open -> CArc::OpenStreamOrFile -> CArc::OpenStream

CMyComPtr<IInArchive> archive;
    FormatIndex = orderIndices[i];
    RINOK(codecs->CreateInArchive(FormatIndex, archive));

虽然封装成了Com DLL形式。导致通过调试就可以知道,其实这个archive就是指向CHandler对象。gzip指向的是CArchieve::NGz::CHandler对象。


后续是CHandler的第二步
(2) if (stream)
    result = archive->Open(stream, &kMaxCheckStartPosition, callback);// 3个参数 stream 压缩文件流 kMaxCheckStartPosition(无效) 解压文件起始位置 callback(无效) 回调类
 CHandler Open 结束

DecompressArchive(arc,
        fi.Size + archiveLink.VolumesSize,
        wildcardCensor, options, extractCallback, extractCallbackSpec, errorMessage, packProcessed)// 解压缩单个文件了  
其中调用了Archieve函数用来进行解压缩
(3) 进行解压缩
    result = archive->Extract(&realIndices.Front(), realIndices.Size(), testMode, extractCallbackSpec);

所以,7z对于解压的封装,中间整个文件的decode。是没有中间流的概念的。并不是和在内存中对解压的大数据进行操作。

使用7z作为lib,只要2步实现该功能
1.修改DLL为Lib目标
2.修改Calling Convention方式为 __cdecl
原创粉丝点击