2012-10-31 8 views
8

Chciałbym zastąpić plik (= usunąć stare i dodać nowe) w archiwum zip w standardzie Delphi XE2/XE3 System.Zip. Ale nie ma metod zamiany/usunięcia. Czy ktokolwiek ma pomysł, jak można to osiągnąć bez potrzeby wyodrębniania wszystkich plików i dodawania ich do nowego archiwum?Delphi XE2 TZipFile: zastępuje plik w archiwum zip

Mam ten kod, ale dodaje „Document.txt” jeszcze raz, czy to już obecny:

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; 

Uwaga: Kiedyś TPAbbrevia przed (to nie praca), ale chciałbym używać teraz jednostki Zip Delphi. Więc proszę nie odpowiadać na coś w rodzaju "użyj innej biblioteki". Dziękuję Ci.

+1

Ty odpowiedziałeś na swoje pytanie. Wbudowana biblioteka ZIP nie obsługuje tej funkcji. –

+0

Może ktoś napisał hack, że to robi? – oxo

+0

Dlaczego nie używasz Abbrevia? Powiedziano mi, że jest bardzo dobra. –

Odpowiedz

12

Polecam Abbrevia, ponieważ jestem stronniczy :), już go znasz i nie wymaga żadnych hacków. Zakaz, że tutaj masz Hack:

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; 

Zastosowanie:

ZipFile.Delete('document.txt'); 
ZipFile.Add(SS, 'document.txt'); 
+0

+1 Czy ten hack rzeczywiście usuwa stary plik z ZIP, czy po prostu usuwa go z tabeli plików lub jak się nazywa? –

+0

Nie fizycznie nie usuwa pliku (plik ZIP rośnie), ale to dobry początek. Spróbuję rozszerzyć kod i usunąć stary plik z FStream i ponownie przeliczyć nagłówek (nowe pozycje plików). – oxo

+1

@David good catch; Powinienem był bliżej przyjrzeć się realizacji. Zaktualizowano bardziej kompletny hack, który usuwa zawartość pliku. –

Powiązane problemy