2012-10-31 10 views
8

Mi piacerebbe sostituire un file (= elimina vecchio e aggiungi nuovo) in un archivio zip con l'unità System.Zip standard Delphi XE2/XE3. Ma non ci sono metodi di sostituzione/cancellazione. Qualcuno ha un'idea di come potrebbe essere raggiunto senza dover estrarre tutti i file e aggiungerli a un nuovo archivio?Delphi XE2 TZipFile: sostituire un file nell'archivio zip

Ho questo codice, ma aggiunge la "Document.txt" ancora una volta se è già presente:

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; 

Nota: ho usato TPAbbrevia prima (che ha fatto il lavoro), ma mi piacerebbe per usare l'unità Zip di Delphi ora. Quindi per favore non rispondere a qualcosa come "usa un'altra libreria". Grazie.

+1

Hai risposto alla tua domanda. La libreria ZIP integrata non supporta questa funzionalità. –

+0

Forse qualcuno ha scritto un trucco che fa? – oxo

+0

Perché non usi Abbrevia? Mi è stato detto che è molto buono. –

risposta

12

Vorrei raccomandare Abbrevia perché sono di parte :), lo sai già, e non richiede alcun hack. A parte ciò, ecco la vostra mod:

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; 

Usage:

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

+1 Questo hack rimuove effettivamente il vecchio file dallo ZIP, o lo rimuove semplicemente dalla tabella dei file o da qualunque cosa venga chiamata? –

+0

No, non rimuove fisicamente il file (il file zip cresce), ma è un buon inizio. Proverò ad estendere il codice ed eliminare il vecchio file da FStream e ricalcolare l'intestazione (nuove posizioni del file). – oxo

+1

@David buona cattura; Avrei dovuto esaminare l'attuazione più da vicino. Aggiornato con un hack più completo che elimina il contenuto del file. –

Problemi correlati