2023-02-02 12:02:14 +03:00

334 lines
12 KiB
ObjectPascal

////////////////////////////////////////////////////////////////////////////////
//
// ****************************************************************************
// * Project : FWZip
// * Unit Name : BuildWithException
// * Purpose : Äåìîíñòðàöèÿ ðàáîòû ñ èñêëþ÷åíèÿìè
// * : ïðè ñîçäàíèè è ðàñïàêîâêå àðõèâà
// * Author : Àëåêñàíäð (Rouse_) Áàãåëü
// * Copyright : © Fangorn Wizards Lab 1998 - 2013.
// * Version : 1.0.10
// * Home Page : http://rouse.drkb.ru
// * Home Blog : http://alexander-bagel.blogspot.ru
// ****************************************************************************
// * Stable Release : http://rouse.drkb.ru/components.php#fwzip
// * Latest Source : https://github.com/AlexanderBagel/FWZip
// ****************************************************************************
//
// Èñïîëüçóåìûå èñòî÷íèêè:
// ftp://ftp.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
// http://zlib.net/zlib-1.2.5.tar.gz
// http://www.base2ti.com/
//
// Äàííûé ïðèìåð ïîêàçûâàåò ðàáîòó ñ ðàçëè÷íûìè îøèáêàìè ìîãóùèìè âîçíèêíóòü
// â ïðîöåññå ñîçäàíèÿ è ðàñïàêîâêè àðõèâà, à òàê-æå ñïîñîáû èõ îáðàáîòêè.
program BuildWithException;
{$APPTYPE CONSOLE}
uses
Windows,
Classes,
SysUtils,
TypInfo,
FWZipConsts,
FWZipWriter,
FWZipReader;
var
Writer: TFWZipWriter;
Reader: TFWZipReader;
Method: TMethod;
hOFStruct: TOFStruct;
hFile: THandle;
//
// Ïðîöåäóðà âûâîäèò ðåçóëüòàò ðàáîòû ôóíêöèè BuildZip
// =============================================================================
procedure ShowBuildResult(Value: TBuildZipResult);
begin
Writeln(GetEnumName(TypeInfo(TBuildZipResult), Integer(Value)));
end;
//
// Ïðîöåäóðà âûâîäèò ðåçóëüòàò ðàáîòû ôóíêöèè Extract
// =============================================================================
procedure ShowManualExtractResult(const ElementName: string;
Value: TExtractResult);
begin
Writeln(Format('%s -> %s', [ElementName,
GetEnumName(TypeInfo(TExtractResult), Integer(Value))]));
end;
//
// ñìîòðè îïèñàíèå îáðàáîò÷èêà íèæå
// =============================================================================
procedure OnException1(Self, Sender: TObject; E: Exception;
const ItemIndex: Integer; var Action: TExceptionAction;
var NewFilePath: string; NewFileData: TMemoryStream);
var
CurrentFilePath: string;
Src: THandleStream;
Dst: TFileStream;
hOFStruct: TOFStruct;
hFile: THandle;
begin
CurrentFilePath := string(TFWZipWriter(Sender)[ItemIndex].FilePath);
NewFilePath := ChangeFileExt(CurrentFilePath, '.tmp');
hFile := OpenFile(PAnsiChar(AnsiString(CurrentFilePath)),
hOFStruct, OF_READ);
try
Src := THandleStream.Create(hFile);
try
Dst := TFileStream.Create(NewFilePath, fmCreate);
try
Dst.CopyFrom(Src, 0);
finally
Dst.Free;
end;
finally
Src.Free;
end;
finally
CloseHandle(hFile);
end;
Action := eaUseNewFilePathAndDel;
end;
//
// ñìîòðè îïèñàíèå îáðàáîò÷èêà íèæå
// =============================================================================
procedure OnException2(Self, Sender: TObject; E: Exception;
const ItemIndex: Integer; var Action: TExceptionAction;
var NewFilePath: string; NewFileData: TMemoryStream);
begin
CloseHandle(hFile);
hFile := INVALID_HANDLE_VALUE;
Action := eaRetry;
end;
//
// ñìîòðè îïèñàíèå îáðàáîò÷èêà íèæå
// =============================================================================
procedure OnException3(Self, Sender: TObject; E: Exception;
const ItemIndex: Integer; var Action: TExceptionAction;
var NewFilePath: string; NewFileData: TMemoryStream);
var
Src: THandleStream;
hOFStruct: TOFStruct;
hFile: THandle;
begin
hFile := OpenFile(
PAnsiChar(AnsiString(TFWZipWriter(Sender)[ItemIndex].FilePath)),
hOFStruct, OF_READ);
try
Src := THandleStream.Create(hFile);
try
NewFileData.CopyFrom(Src, 0);
finally
Src.Free;
end;
finally
CloseHandle(hFile);
end;
Action := eaUseNewFileData;
end;
//
// ñìîòðè îïèñàíèå îáðàáîò÷èêà íèæå
// =============================================================================
procedure OnDuplicate(Self, Sender: TObject;
var Path: string; var Action: TDuplicateAction);
begin
Path := MakeUniqueName(Path);
Action := daUseNewFilePath;
end;
var
I: Integer;
begin
SetCurrentDir(ExtractFilePath(ParamStr(0)));
try
// Ñàìàÿ áàíàëüíàÿ îøèáêà ïðè ñîçäàíèè àðõèâà - ýòî îòñóòñòâèå äîñòóïà
// ê äîáàâëÿåìîìó â àðõèâ ôàéëó.
// Íàïðèìåð âîò òàêîé êîä ïûòàåòñÿ çààðõèâèðîâàòü ñîäåðæèìîå êîðíåâîé
// ïàïêè â êîòîðîé èñêóññòâåííî çàëî÷åí îäèí èç ýëåìåíòîâ
//  ýòîì ñëó÷àå âîçíèêíåò îøèáêà äîñòóïà ê çàëî÷åíîìó ôàéëó.
// Åñëè íå íàçíà÷åíû îáðàáîò÷èêè èñêëþ÷åíèé, òî òàêîé ôàéë áóäåò ïðîïóùåí
// (äåéñòâèå ïî óìîë÷àíèþ eaSkip) è ôóíêöèÿ BuildZip
// âåðíåò ñëåäóþùèå êîäû îøèáîê:
// brFailed - â ñëó÷àå åñëè â ïàïêå íåáûëî äðóãèõ ôàéëîâ
// êðîìå çàëî÷åííîãî (ò.å. â àðõèâ äîáàâëÿòü íå÷åãî)
// brPartialBuild - â ñëó÷àå åñëè â àðõèâ âñå-æå áûëè äîáàâëåíû êàêèå-ëèáî ôàéëû,
// íî íåêîòîðûå èç íèõ áûëè ïðîïóùåíû
Writer := TFWZipWriter.Create;
try
Writer.AddFolder('', '..\..\', '*.pas', False);
ForceDirectories('..\DemoResults\');
// ëî÷èì îäèí èç ôàéëîâ äëÿ äåìîíñòðàöèè
hFile := OpenFile(PAnsiChar(AnsiString('..\..\' + Writer[0].FileName)),
hOFStruct, OF_WRITE);
try
Write('BuildWithException1.zip -> ');
ShowBuildResult(Writer.BuildZip('..\DemoResults\BuildWithException1.zip'));
finally
CloseHandle(hFile);
end;
finally
Writer.Free;
end;
// óçíàòü êàêèå ôàéëû áûëè ïðîïóùåíû è ïîïûòàòüñÿ èñïðàâèòü äàííóþ ñèòóàöèþ
// ìîæíî ïåðåêðûòèåì ñîáûòèÿ OnException
// Â ñëåäóþùåì ïðèìåðå áóäåò ïîêàçàíî êàê âñå-æå îáðàáîòàòü òàêóþ îøèáêó
// è äîáàâèòü ïðîáëåìíûé ôàéë â àðõèâ
Writer := TFWZipWriter.Create;
try
Writer.AddFolder('', '..\..\', '*.pas', False);
ForceDirectories('..\DemoResults\');
// ëî÷èì îäèí èç ôàéëîâ äëÿ äåìîíñòðàöèè
hFile := OpenFile(PAnsiChar(AnsiString('..\..\' + Writer[0].FileName)),
hOFStruct, OF_WRITE);
try
// Íàçíà÷àåì îáðàáîò÷èê ÷åðåç êîòîðûé ìû áóäåì îáðàáàòûâàòü îøèáêó
//  îáðàáîò÷èêå OnException1 áóäåò ñîçäàâàòüñÿ êîïèÿ ôàéëà
// ïîñëå ÷åãî ìû óêàæåì â ïàðàìåòðå NewFilePath íîâûé ïóòü ê ôàéëó,
// à ñâîéñòâî Action âûñòàâèì eaUseNewFilePathAndDel
// Òàêèì îáðàçîì ìû óâåäîìëÿåì FWZip ÷òî íóæíî ïîâòîðèòü ïîïûòêó
// àðõèâàöèè ôàéëà, ïðè ýòîì íåîáõîäèìî èñïîëüçîâàòü íîâûé ïóòü ê ôàéëó,
// ïîñëå ÷åãî äàííûé ôàéë ñëåäóåò óäàëèòü.
Method.Code := @OnException1;
Method.Data := Writer;
Writer.OnException := TZipBuildExceptionEvent(Method);
Write('BuildWithException2.zip -> ');
ShowBuildResult(Writer.BuildZip('..\DemoResults\BuildWithException2.zip'));
// âòîðîé âàðèàíò, îáðàáîòêè ïîêàçàí â îáðàáîò÷èêå OnException2
// â íåì ìû ñíèìàåì èññêóñòâåííóþ áëîêèðîâêó ôàéëà è âûñòàâëÿåì
// ñâîéñòâî Action â eaRetry.
// Òàêèì îáðàçîì ìû óâåäîìëÿåì FWZip ÷òî íóæíî ïîâòîðèòü ïîïûòêó
// àðõèâàöèè ôàéëà
Method.Code := @OnException2;
Method.Data := Writer;
Writer.OnException := TZipBuildExceptionEvent(Method);
Write('BuildWithException3.zip -> ');
ShowBuildResult(Writer.BuildZip('..\DemoResults\BuildWithException3.zip'));
// äëÿ äåìîíñòðàöèè âîçâðàùàåì áëîêèðîâêó íà ìåñòî
if hFile = INVALID_HANDLE_VALUE then
hFile := OpenFile(PAnsiChar(AnsiString('..\..\' + Writer[0].FileName)),
hOFStruct, OF_WRITE);
// òðåòèé âàðèàíò, îáðàáîòêè ïîêàçàí â îáðàáîò÷èêå OnException3
// â íåì ìû çàãðóæàåì ëþáûì ñïîñîáîì äàííûå ôàéëà â ñòðèì è
// âûñòàâëÿåì ñâîéñòâî Action â eaUseNewFileData
// Òàêèì îáðàçîì äàííûå áóäóò áðàòüñÿ íåïîñðåäñòâåííî èç ñòðèìà
// NewFileData
Method.Code := @OnException3;
Method.Data := Writer;
Writer.OnException := TZipBuildExceptionEvent(Method);
Write('BuildWithException4.zip -> ');
ShowBuildResult(Writer.BuildZip('..\DemoResults\BuildWithException4.zip'));
// îðèåíòèðóÿñü íà òèï èñêëþ÷åíèÿ ìîæíî ðåàëèçîâûâàòü ðàçíóëþ ëîãèêó îáðàáîò÷èêà.
// åñëè âû íå çíàåòå êàê îáðàáîòàòü òî èëè èíîå èñêëþ÷åíèå,
// ñëåäóåò âûñòàâèòü ñâîéñòâî Action â eaSkip (âûñòàâëåíî ïî óìîë÷àíèþ)
// äëÿ òîãî ÷òîáû ïðîïóñòèòü ïðîáëåìíûé ôàéë, èëè eaAbort,
// ïðåðâàâ òàêèì îáðàçîì ñîçäàíèå àðõèâà.
finally
if hFile <> INVALID_HANDLE_VALUE then
CloseHandle(hFile);
end;
finally
Writer.Free;
end;
// Ïðè ðàñïàêîâêå ÷àñòîé îøèáî÷íîé ñèòóàöèåé ÿâëÿåòñÿ ïîïûòêà
// ïåðåçàïèñè óæå ñóùåñòâóþùåãî íà äèñêå ôàéëà, ëèáî îøèáêà
// ðàñïàêîâêè àðõèâà, ñîçäàííîãî ñòîðîííèì àðõèâàòîðîì.
// Îáðàáîòêà îøèáêè ðàñïàêîâêè ðåøàåòñÿ èñïîëüçîâàíèåì áîëåå
// íîâîé âåðñèè ZLib (ñì. Readme.txt ïóíêò 9)
// Âîçíèêíîâåíèå îøèáêè ïî äðóãèì ïðè÷èíàì ïðèâåäåò ê âîçíèêíîâåíèþ
// ñîáûòèÿ OnException. Åñëè äàííîå ñîáûòèå íå ïåðåêðûòî,
// òî â ñëó÷àå âûçîâà ìåòîäà TFWZipReader.ExtractAll
// ðàñïàêîâêà àðõèâà áóäåò îñòàíîâëåíà.
//  ñëó÷àå, åñëè äàííîå ñîáûòèå ïåðåêðûòî, òî ðåøåíèå
// î îñòàíîâêå ðàñïàêîâêè äîëæåí ïðèíèìàòü ïðîãðàììèñò,
// âûñòàâëåíèåì ôëàãà Handled:
// (Handled = True, èñêëþ÷åíèå îáðàáîòàíî, ìîæíî ïðîäîëæèòü ðàñïàêîâêó)
// äëÿ äåìîíñòðàöèè ïðîýìóëèðóåì îøèáêó ïåðåçàïèñè,
// äëÿ ýòîãî íóæíî äâàæäû ðàñïàêîâàòü îäèí è òîò-æå àðõèâ
// â îäíó è òó-æå ïàïêó
Reader := TFWZipReader.Create;
try
Reader.LoadFromFile('..\DemoResults\BuildWithException1.zip');
ForceDirectories('..\DemoResults\BuildWithExceptionUnpack\');
// ðàñïàêîâûâàåì ïåðâûé ðàç
Reader.ExtractAll('..\DemoResults\BuildWithExceptionUnpack\');
// òåïåðü ïðîáóåì ðàñïàêîâàòü ïîâòîðíî.
// èñêëþ÷åíèÿ â äàííîì ñëó÷àå íå ïðîèçîéäåò, íî âñå ýëåìåíòû áóäóò ïðîïóùåíû
Reader.ExtractAll('..\DemoResults\BuildWithExceptionUnpack\');
// ïðîïóñê ýëåìåíòîâ ìîæíî óâèäåòü è ïðè ðó÷íîé ðàñïàêîâêå.
// ò.ê. âûçîâ Reader[I].Extract â îòëè÷èå îò Reader.ExtractAll
// âîçâðàùàåò ðåçóëüòàò
Writeln('Manual extract:');
for I := 0 to Reader.Count - 1 do
ShowManualExtractResult(
string(Reader[I].FileName),
Reader[I].Extract('..\DemoResults\BuildWithExceptionUnpack\', ''));
// êàê ìîæíî çàìåòèòü, âñå ýëåìåíòû äåéñòâèòåëüíî áûëè ïðîïóùåíû
// (Reader[I].Extract âåðíóë erSkiped äëÿ êàæäîãî ýëåìåíòà)
// Äëÿ îáðàáîòêè äàííîé ñèòóàöèè â ðåæèìå àâòîìàòè÷åñêîé ðàñïàêîâêè (ExtractAll)
// íåîáõîäèìî ïåðåêðûòü ñîáûòèå OnDuplicate ó êëàññà TFWZipReader.
//  ñëó÷àå ðó÷íîé ðàñïàêîâêè, ïåðåêðûâàòü ñîáûòèå OnDuplicate òðåáóåòñÿ
// ó êàæäîãî ýëåìåíòà (Reader.Items[èíäåêñ ýëåìåíòà].OnDuplicate)
Method.Code := @OnDuplicate;
Method.Data := Reader;
Reader.OnDuplicate := TZipDuplicateEvent(Method);
// òåïåðü ïîïðîáóåì ïîâòîðíî ðàñïàêîâàòü.
// ïðè âîçíèêíîâåíèè ñîáûòèÿ OnDuplicate â îáðàáîò÷èêå ýëåìåíòó áóäåò
// íàçíà÷åíî íîâîå èìÿ è ïàðàìåòð Action áóäåò âûñòàâëåí â daUseNewFilePath.
// Òàêèì îáðàçîì ìû óêàæåì TFWZipReader-ó ÷òî íåîáõîäèìî ðàñïàêîâàòü
// ôàéë ñ íîâûì èìåíåì...
// (ò.å. ïîëó÷èì àíàëîã ñîçäàíèÿ ôàéëîâ â ïðîâîäíèêå Windows, íàïðèìåð:
// New folder -> New folder (2) -> New folder (3) è ò.ä.)
Reader.ExtractAll('..\DemoResults\BuildWithExceptionUnpack\');
finally
Reader.Free;
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.