2012-10-31 13 views
8

Tôi muốn thay thế tệp (= xóa cũ và thêm mới) trong kho lưu trữ zip với đơn vị System.Zip Delphi XE2/XE3. Nhưng không có phương pháp thay thế/xóa. Có ai có một ý tưởng làm thế nào nó có thể đạt được mà không cần phải giải nén tất cả các tập tin và thêm chúng vào một kho lưu trữ mới?Delphi XE2 TZipFile: thay thế một tệp trong kho lưu trữ zip

tôi có mã này, nhưng nó thêm "Document.txt" một lần nữa nếu nó đã hiện diện:

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; 

Lưu ý: Tôi sử dụng TPAbbrevia trước (mà đã làm các công việc), nhưng tôi muốn để sử dụng đơn vị Zip của Delphi ngay bây giờ. Vì vậy, xin vui lòng không trả lời một cái gì đó như "sử dụng thư viện khác". Cảm ơn bạn.

+1

Bạn đã trả lời câu hỏi của riêng bạn. Thư viện ZIP tích hợp không hỗ trợ chức năng đó. –

+0

Có thể ai đó đã viết một bản hack mà nó làm? – oxo

+0

Tại sao bạn không sử dụng Abbrevia? Tôi đã nói rằng nó rất tốt. –

Trả lời

12

Tôi muốn giới thiệu Abbrevia vì tôi thiên vị :), bạn đã biết điều đó và không yêu cầu bất kỳ hack nào. Chặn điều đó, đây là hack của bạn:

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; 

Cách sử dụng:

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

+1 Việc đó có thực sự xóa tệp cũ khỏi ZIP hay không, chỉ cần xóa tệp đó khỏi bảng tệp hoặc bất kỳ tệp nào được gọi? –

+0

Không có nó không thể loại bỏ các tập tin (tập tin zip phát triển), nhưng đó là một khởi đầu tốt. Tôi sẽ cố gắng mở rộng mã và xóa tệp cũ khỏi FStream và tính toán lại tiêu đề (vị trí tệp mới). – oxo

+1

@David bắt tốt; Tôi nên đã xem xét việc thực hiện gần hơn. Cập nhật với một hack hoàn chỉnh hơn mà không xóa nội dung tập tin. –