Delphi XE2 TZipFile: замена файла в zip архиве
Я хотел бы заменить файл (= удалить старый и добавить новый) в zip-архиве стандартной системой Delphi XE2/XE3.Zip unit. Но нет методов replace/delete. Кто-нибудь знает, как это можно сделать без необходимости извлекать все файлы и добавлять их в новый архив?
У меня есть этот код, но он добавляет "документ.txt " еще раз, если он уже присутствует:
var
ZipFile: TZipFile;
SS: TStringStream;
const
ZipDocument = 'E:document.zip';
begin
ZipFile := TZipFile.Create; //Zipfile: TZipFile
SS := TStringStream.Create('hello');
try
if FileExists(ZipDocument) then
ZipFile.Open(ZipDocument, zmReadWrite)
else
ZipFile.Open(ZipDocument, zmWrite);
ZipFile.Add(SS, 'document.txt');
ZipFile.Close;
finally
SS.Free;
ZipFile.Free;
end;
end;
Примечание: я использовал TPAbbrevia раньше (это сделало работу), но я хотел бы использовать Теперь это почтовый ящик Дельфи. Поэтому, пожалуйста, не отвечайте что-то вроде "использовать другую библиотеку". Спасибо.
1 ответов
Я бы рекомендовал аббревиатуру, потому что я предвзят :), вы уже знаете это, и это не требует никаких хаков. За исключением этого, вот ваш Хак:
type
TZipFileHelper = class helper for TZipFile
procedure Delete(FileName: string);
end;
{ TZipFileHelper }
procedure TZipFileHelper.Delete(FileName: string);
var
i, j: Integer;
StartOffset, EndOffset, Size: UInt32;
Header: TZipHeader;
Buf: TBytes;
begin
i := IndexOf(FileName);
if i <> -1 then begin
// Find extents for existing file in the file stream
StartOffset := Self.FFiles[i].LocalHeaderOffset;
EndOffset := Self.FEndFileData;
for j := 0 to Self.FFiles.Count - 1 do begin
if (Self.FFiles[j].LocalHeaderOffset > StartOffset) and
(Self.FFiles[j].LocalHeaderOffset <= EndOffset) then
EndOffset := Self.FFiles[j].LocalHeaderOffset;
end;
Size := EndOffset - StartOffset;
// Update central directory header data
Self.FFiles.Delete(i);
for j := 0 to Self.FFiles.Count - 1 do begin
Header := Self.FFiles[j];
if Header.LocalHeaderOffset > StartOffset then begin
Header.LocalHeaderOffset := Header.LocalHeaderOffset - Size;
Self.FFiles[j] := Header;
end;
end;
// Remove existing file stream
SetLength(Buf, Self.FEndFileData - EndOffset);
Self.FStream.Position := EndOffset;
if Length(Buf) > 0 then
Self.FStream.Read(Buf[0], Length(Buf));
Self.FStream.Size := StartOffset;
if Length(Buf) > 0 then
Self.FStream.Write(Buf[0], Length(Buf));
Self.FEndFileData := Self.FStream.Position;
end;
end;
использование:
ZipFile.Delete('document.txt');
ZipFile.Add(SS, 'document.txt');