2012-10-31 2 views
8

zip 아카이브에서 파일을 (= 오래된 것을 삭제하고 새로 추가하는) 델파이 XE2/XE3 표준 System.Zip 유닛으로 대체하고 싶습니다. 그러나 대체/삭제 방법은 없습니다. 누구든지 모든 파일을 추출하지 않고 새로운 아카이브에 추가 할 필요없이 어떻게 달성 할 수 있었는지 생각할 수 있습니까?Delphi XE2 TZipFile : zip 아카이브의 파일 바꾸기

나는이 코드를 가지고 있지만, 그것은 이미의 경우는 한번 더 "document.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를 사용하지만, 내가 좋아하는 것 지금 델파이의 Zip 장치를 사용합니다. 그러니 "다른 도서관 이용"과 같은 대답을하지 마십시오. 고맙습니다.

+1

. 내장 된 ZIP 라이브러리는 해당 기능을 지원하지 않습니다. –

+0

누군가가 해킹을 작성했을 수도 있습니다. – oxo

+0

Abbrevia를 사용하지 않는 이유는 무엇입니까? 나는 그것이 아주 좋은 것이라고 들었다. –

답변

12

나는 편견이 있기 때문에 Abbrevia를 권하고 싶습니다. 이미 알고 있습니다. 해킹이 필요하지 않습니다. 이 없다면, 여기 해킹 :

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'); 
+0

+1 해킹은 실제로 ZIP에서 이전 파일을 제거합니까, 아니면 그냥 파일 테이블이나 그 파일이 호출 된 모든 파일에서 제거합니까? –

+0

아니요 물리적으로 파일을 지우지 않습니다 (zip 파일이 커짐). 그러나 좋은 시작입니다. 코드를 확장하고 FStream에서 이전 파일을 삭제하고 헤더 (새 파일 위치)를 다시 계산하려고합니다. – oxo

+1

@David 좋은 캐치; 나는 그 구현을 더 가깝게보아야 만했다. 파일 내용을 삭제하는보다 완벽한 해킹으로 업데이트되었습니다. –