학습 노트: 7z가델파이에서의 응용

15502 단어
최근에 메일을 보내는 기능이 생겨서 로그 파일을 메일로 보내서 분석에 사용해야 하는데 로그 파일이 엄청 커질 수도 있고 하루에 800M의 크기를 측정할 수도 있다.그래서 압축은 불가피하다. 델피의 기본 압축 알고리즘은 반나절 동안 잘 안 돼서 7z를 봤는데 윈도우즈 밑에 dll이 있으니 사용하자.
다운로드 7z.dll,delphi의 개발 sdk 파일,sevenzip.pas.이 두 개만 있으면 돼요.
압축
사용이 매우 간단합니다.
procedure TForm1.Button1Click(Sender: TObject);
var
  Arch: I7zOutArchive;
  Counter: Integer;
  sZipFile: string;
begin
  OpenDialog1.Filter := '    |*.*';
  OpenDialog1.Options := OpenDialog1.Options + [ofAllowMultiSelect];
  if OpenDialog1.Execute then
  begin
    Memo1.Lines.Append('    ');
    Arch := CreateOutArchive(CLSID_CFormat7z);
    Arch.SetProgressCallback(nil, ProgressCallback);
    for Counter := 0 to OpenDialog1.Files.Count - 1 do
      Arch.AddFile(OpenDialog1.Files[Counter], ExtractFileName(OpenDialog1.Files[Counter]));

    SetCompressionLevel(Arch, 5);
    SevenZipSetCompressionMethod(Arch, m7LZMA);//
    sZipFile := FRootPath+'test.7z';
    Arch.SaveToFile(sZipFile);
    Memo1.Lines.Append('    ,     :' + sZipFile);
    CalcZipScale(sZipFile, ProgressBar1.Max);    
  end;
end;

이 방법은 파일 선택 상자를 통해 여러 파일을 압축하여 하나의 압축 패키지로 만들 수 있습니다.여기서 주의해야 할 것은 m7LZMA라는 알고리즘의 압축이 특히 높아서 텍스트 유형을 겨냥한 것이 좋을 것 같다는 것이다.나는 400M의 텍스트를 압축해서 5M 정도 시험해 보았다.이 압축률은 그래도 매우 볼 만하다.
또한 디렉토리 전체를 압축하는 방법도 간단합니다.
procedure TForm1.Button3Click(Sender: TObject);
var
  Arch: I7zOutArchive;
  Counter: Integer;
  sZipFile: string;
begin
  if not DirectoryExists(edtPath.Text) then
  begin
    ShowMessage('       ');
    edtPath.SetFocus;
  end;

  Memo1.Lines.Add('    ');
  Arch := CreateOutArchive(CLSID_CFormat7z);
  Arch.SetProgressCallback(nil, ProgressCallback);
  Arch.AddFiles(edtPath.Text, 'memData', '*.*', False);

  SetCompressionLevel(Arch, 5);
  SevenZipSetCompressionMethod(Arch, m7LZMA);//
  sZipFile := FRootPath+'path.7z';
  Arch.SaveToFile(sZipFile);
  Memo1.Lines.Append('    ,     :' + sZipFile);
  CalcZipScale(sZipFile, ProgressBar1.Max);
end;

크게 다르지 않은 것은 압축 방법을 호출할 때 AddFiles를 사용하는 것입니다. 이 방법의 매개 변수는 다음과 같습니다.
procedure AddFiles(const Dir, Path, Wildcard: string; recurse: boolean); stdcall;

Dir:압축할 디렉토리
Path: 압축된 패키지의 디렉터리 (압축된 패키지의 루트 디렉터리)
Wildcard: 와일드카드, 파일 필터(*.*)
recurse: 하위 디렉터리로 귀속
다른 압축은 제가 해 보지 않았습니다. 7z를 만드는 패키지는 winrar로 어차피 열고 풀 수 있습니다.
압축 풀기
7z도 압축 해제 알고리즘을 제공했지만 서로 다른 압축 알고리즘이 생성한 압축 패키지 형식은 다르기 때문에 압축 해제 유형을 지정하여 압축을 해제해야 한다.그러나 나는 7z에서 지원하는 알고리즘의 유형이 여전히 완전한 것을 보고 If 목록을 만들었다.
먼저 스트레스를 푸는 방법을 살펴보자.
procedure TForm1.Button2Click(Sender: TObject);
var
  Arch: I7zInArchive;
  Counter: Integer;
  sExtractPath: string;
begin
  OpenDialog1.Filter := '    |*.zip;*.rar;*.7z';
  OpenDialog1.Options := OpenDialog1.Options - [ofAllowMultiSelect];
  if OpenDialog1.Execute then
  begin
    Memo1.Lines.Append('    ');
    try
      Arch := GetInArchiveByFileExt(ExtractFileExt(OpenDialog1.FileName));
      Arch.SetProgressCallback(nil, ProgressCallback);
      Arch.OpenFile(OpenDialog1.FileName);
      for Counter := 0 to Arch.NumberOfItems - 1 do
      begin
        if not Arch.ItemIsFolder[Counter] then
          Memo1.Lines.Append('' + Arch.ItemPath[Counter]);
      end;

      sExtractPath := FRootPath + getShotFileName(ExtractFileName(OpenDialog1.FileName));
      if ForceDirectories(sExtractPath) then
      begin
        Arch.ExtractTo(sExtractPath);
        Memo1.Lines.Append('    ');
      end
      else
        ShowMessage('         ');
    except
      on e: Exception do
        Memo1.Lines.Add('' + e.Message)
    end;

    Arch := nil;
    Memo1.Lines.Add('-----------------------------------------------------------');
  end;
end;

압축을 풀 때 ExtractTo를 호출하여 압축을 풀 수 있습니다. 간단합니다.다만 접미사를 통해 특정한 압축 해제 대상을 선택하려면 단독으로 처리해야 한다. 방법은 다음과 같다.
function TForm1.GetInArchiveByFileExt(AExt: string): I7zInArchive;
var
  sExt: string;
begin
  sExt := UpperCase(AExt);
  if (sExt='.ZIP') or (sExt='.JAR') or (sExt='.XPI') then
    Result := CreateInArchive(CLSID_CFormatZip)
  else if (sExt='.BZ2') or (sExt='.BZIP2') or (sExt='.TBZ2') or (sExt='.TBZ') then
    Result := CreateInArchive(CLSID_CFormatBZ2)
  else if (sExt='.RAR') or (sExt='.R00') then
    Result := CreateInArchive(CLSID_CFormatRar)
  else if (sExt='.ARJ') then
    Result := CreateInArchive(CLSID_CFormatArj)
  else if (sExt='.Z') or (sExt='.TAZ') then
    Result := CreateInArchive(CLSID_CFormatZ)
  else if (sExt='.LZH') or (sExt='.LHA') then
    Result := CreateInArchive(CLSID_CFormatLzh)
  else if (sExt='.7Z') then
    Result := CreateInArchive(CLSID_CFormat7z)
  else if (sExt='.CAB') then
    Result := CreateInArchive(CLSID_CFormatCab)
  else if (sExt='.NSIS') then
    Result := CreateInArchive(CLSID_CFormatNsis)
  else if (sExt='.LZMA') then
    Result := CreateInArchive(CLSID_CFormatLzma)
  else if (sExt='.LZMA86') then
    Result := CreateInArchive(CLSID_CFormatLzma86)
  else if (sExt='.EXE') then
    Result := CreateInArchive(CLSID_CFormatPe)
  else if (sExt='.PE') or (sExt='.DLL') or (sExt='.SYS') then
    Result := CreateInArchive(CLSID_CFormatPe)
  else if (sExt='.ELF') then
    Result := CreateInArchive(CLSID_CFormatElf)
  else if (sExt='.MACHO') then
    Result := CreateInArchive(CLSID_CFormatMacho)
  else if (sExt='.UDF') then
    Result := CreateInArchive(CLSID_CFormatUdf)
  else if (sExt='.XAR') then
    Result := CreateInArchive(CLSID_CFormatXar)
  else if (sExt='.MUB') then
    Result := CreateInArchive(CLSID_CFormatMub)
  else if (sExt='.HFS') or (sExt='.CD') then
    Result := CreateInArchive(CLSID_CFormatHfs)
  else if (sExt='.DMG') then
    Result := CreateInArchive(CLSID_CFormatDmg)
  else if (sExt='.MSI') or (sExt='.DOC') or (sExt='.XLS') or (sExt='.PPT') then
    Result := CreateInArchive(CLSID_CFormatCompound)
  else if (sExt='.WIM') or (sExt='.SWM') then
    Result := CreateInArchive(CLSID_CFormatWim)
  else if (sExt='.ISO') then
    Result := CreateInArchive(CLSID_CFormatIso)
  else if (sExt='.BKF') then
    Result := CreateInArchive(CLSID_CFormatBkf)
  else if (sExt='.CHM') or (sExt='.CHI') or (sExt='.CHQ') or (sExt='.CHW')
          or (sExt='.HXS') or (sExt='.HXI') or (sExt='.HXR') or (sExt='.HXQ')
          or (sExt='.HXW') or (sExt='.LIT') then
    Result := CreateInArchive(CLSID_CFormatChm)
  else if  (sExt='.001') then
    Result := CreateInArchive(CLSID_CFormatSplit)
  else if  (sExt='.RPM') then
    Result := CreateInArchive(CLSID_CFormatRpm)
  else if  (sExt='.DEB') then
    Result := CreateInArchive(CLSID_CFormatDeb)
  else if  (sExt='.CPIO') then
    Result := CreateInArchive(CLSID_CFormatCpio)
  else if  (sExt='.TAR') then
    Result := CreateInArchive(CLSID_CFormatTar)
  else if  (sExt='.GZ') or (sExt='.GZIP') or (sExt='.TGZ') or (sExt='.TPZ') then
    Result := CreateInArchive(CLSID_CFormatGZip)
  else
    Result := CreateInArchive(CLSID_CFormatZip);
end;

7z의 완성도가 이렇게 높을 줄은 몰랐어요. 그래도 아주 편해요.
 
후기net 플랫폼에서 7z를 호출한 적이 있는데, 단지 셸 방식으로 호출한 7z에 불과하다.exe.명령을 사용하는 것은 좀 번거로울 것 같아서, dll을 사용하여 프로그램에 집적하는 것은 그래도 매우 편리하다.

좋은 웹페이지 즐겨찾기