2012-10-31 8 views
8

Ich möchte eine Datei (= löschen und neu hinzufügen) in einem Zip-Archiv mit dem Delphi XE2/XE3 Standard System.Zip-Gerät ersetzen. Aber es gibt keine Methoden zum Ersetzen/Löschen. Hat jemand eine Idee, wie es erreicht werden könnte, ohne alle Dateien extrahieren zu müssen und sie einem neuen Archiv hinzufügen zu müssen?Delphi XE2 TZipFile: Ersetzen Sie eine Datei im Zip-Archiv

ich diesen Code, aber es fügt die „Document.txt“ einmal mehr, wenn es bereits vorhanden:

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; 

Hinweis: Früher habe ich TPAbbrevia vor (die die Arbeit geleistet haben), aber ich möchte Jetzt Delphi's Zip-Einheit verwenden. Also antworte bitte nicht wie "Benutze eine andere Bibliothek". Vielen Dank.

+1

Sie haben Ihre eigene Frage beantwortet. Die integrierte ZIP-Bibliothek unterstützt diese Funktionalität nicht. –

+0

Vielleicht hat jemand einen Hack geschrieben, dass es tut? – oxo

+0

Warum benutzen Sie nicht Abbrevia? Mir wurde gesagt, dass es sehr gut ist. –

Antwort

12

Ich würde Abbrevia empfehlen, weil ich voreingenommen bin :), Sie kennen es bereits, und es erfordert keine Hacks. Abgesehen davon, hier ist der 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; 

Verbrauch:

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

+1 Entfernt dieser Hack tatsächlich die alte Datei aus der ZIP oder entfernt sie sie einfach aus der Dateitabelle oder wie sie auch heißt? –

+0

Nein, es entfernt die Datei nicht physisch (die ZIP-Datei wächst), aber es ist ein guter Anfang. Ich werde versuchen, den Code zu erweitern und die alte Datei aus FStream zu löschen und die Kopfzeile neu zu berechnen (neue Dateipositionen). – oxo

+1

@David guter Fang; Ich hätte die Implementierung näher betrachten sollen. Mit einem vollständigeren Hack aktualisiert, der Dateiinhalte löscht. –

Verwandte Themen