最近做個發郵件的功能,需要將日志文件通過郵件發送回來用於分析,但是日志文件可能會超級大,測算下來一天可能會有800M的大小。所以壓縮是不可避免了,delphi中的默認壓縮算法整了半天不太好使,就看了看7z,在windows下有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,只不過是使用shell方式調用的7z.exe。用命令感覺會麻煩一些,使用dll集成在程序中還是挺方便的。