2009-11-20 6 views
8

Connaissez-vous un composant gratuit, compatible avec Delphi ou XE pour gérer les archives ZIP (en fait, lire uniquement le contenu des archives et extraire les fichiers requis)?Composant ZIP freeware pour Delphi 2010/Delphi XE?

S'il vous plaît pas de betas.

J'ai pensé à ZipForge de ComponentAce, mais c'est gratuit seulement pour un usage personnel. Aucune distribution de logiciel autorisée.

+0

Avez-vous seulement besoin d'encodage/décodage ou les deux? –

+0

@Ritsaert Hornstra Eh bien, à la fois je crois. –

+1

Remarque: A partir de Delphi XE2, le support des fichiers ZIP a été ajouté: [http://docwiki.embarcadero.com/Libraries/Seattle/en/System.Zip.TZipFile.ExtractAll] [http: // delphiblog.twodesk.com/native-zip-file-support-in-delphi-xe2] Il leur a fallu un moment cependant! – Ampere

Répondre

16

Vous pouvez obtenir le ABRÉVIA TurboPower pour 2010 de: http://tpabbrevia.sourceforge.net/

+0

TurboPower ABRÉVIA \t compression des données \t 9 septembre 2008 Il semble être ni testé ni mis à jour pour Delphi 2010 :( –

+2

J'ai mis à jour l'URL depuis la version de ABRÉVIA sur SourceForge ne supporte Delphi 2010/XE et a des tests unitaires. –

4

vous pouvez jeter un oeil à this si vous aimez 7zip

+1

Il y a un peu d'information manquante sur cette page, il y a ce lien: http://www.7-zip.org/sdk.html mais cela ne gère pas l'API de 7z.dll, et j'ai lu qu'il y a un 7za.dll qui a une interface COM (en d'autres termes: a une bibliothèque de types à importer) –

+0

Oui, c'est prometteur Merci –

+0

J'accepte cette réponse, elle est juste intéressante et utile pour moi Merci –

1

J'aime le TZipMaster WinZip compatible pour Delphi, disponible ici: http://www.delphizip.org/

TZipMaster est un VCL non visuel wrapper créé par ChrisVleghert et EricW.Engler pour leur Zip freeware et décompresser les DLL.

Ces DLL sont basées sur le InfoZip officiel Freeware Zip/source Décompressez le code , mais ne sont pas équivalents à DLLs de InfoZIP. Le code source InfoZip a été modifié pour améliorer la facilité d'utilisation, la puissance et la flexibilité pour une utilisation avec Delphi et C++ Builder.

En outre, cette question a been covered before sur Stack Overflow, ce qui peut générer d'autres solutions pour vous.

+0

TZipMaster (avant la version v1. 79) ne peut pas être construit avec succès dans D2009 version de 1.79 fonctionnera alors dans l'environnement Unicode, il a toujours les mêmes limitations que les versions précédentes. Il n'est pas compatible avec D2010 ou n'est pas testé. –

+0

ZipMaster semble être maintenant compatible, au moins je vois des corrections de bugs dans les nouvelles. Merci pour suggestion! –

0

DotNetZip est une bibliothèque de code managé (.NET), qui expose une interface COM.

Gratuit.
Open source
MS-PL sous licence.

+1

Plate-forme incorrecte et surcharges de code trop importantes pour une application Delphi. –

1

Si la distribution d'une DLL ActiveX avec votre projet n'est pas un problème pour vous, alors Chilkat Zip (http://www.chilkatsoft.com/zip-activex.asp) semble faire l'affaire. Delphi exemples sont ici: http://www.example-code.com/delphi/zip.asp

3

Si vous avez seulement besoin de décodage (développé pour Delphi 2007, non encore testé sous Delphi 2010/XE):

unit UnitZip; 

interface 

uses 
    SysUtils, Classes; 

type 
    EZipException = class(Exception); 

    TZipFileInfo = record 
    LastModified:      TDateTime; 
    Crc32:        Longword; 
    CompressedSize:     Longword; 
    UncompressedSize:     Longword; 
    end; 

    TZipFileReader = class 
    private 
    // Information about the memory mapped file 
    FFileHandle:      THandle; 
    FFileMapping:      THandle; 
    FMappedAddress:     Pointer; 
    // Location of the ZIPfile in memory. Currently we only support memory mapped ZIPfiles without disk spanning. 
    FStart:       Pointer; 
    FSize:        Longword; 
    // ZIP file contents 
    FFilenames:      TStrings; 
    function GetZipFileInfo   (const FileName: AnsiString): TZipFileInfo; 
    public 
    constructor Create     (const FileName: string; ZipStartOffset: Int64 = 0; Size: Longword = 0); overload; 
    constructor Create     (const ResourceName, ResourceType: string; Instance: HMODULE = 0); overload; 
    constructor Create     (Buffer: Pointer; Size: Longword); overload; 
    destructor Destroy;    override; 
    function GetFile    (const FileName: string): TBytes; overload; 
    function GetFile    (FileID: Integer): TBytes; overload; 
    property FileNames:    TStrings read FFileNames; 
    property FileInfo    [ const FileName: AnsiString ]: TZipFileInfo read GetZipFileInfo; 
    end; 

implementation 

uses 
    ZLib, Windows; 

const 
    cResourceNotFound = 'Resource not found: %s.%s.'; 
    cResourceNotLoaded = 'Resource not loaded: %s.%s.'; 
    cCannotOpenFile  = 'Cannot open file %s: OS error: %d.'; 
    cCannotGetFileSize = 'Cannot get file size of file %s: OS error: %d.'; 
    cCannotMapFile  = 'Cannot create file mapping of file %s: OS error: %d.'; 
    cZipFileTooSmall = 'ZIP file is too small.'; 
    cZipFileFormatError = 'ZIP file is invalid.'; 
    cZipBufferInvalid = 'ZIP memory buffer is invalid.'; 
    cUnsupportedMethod = 'ZIP unsupported compression method: %d.'; 
    cFileNotFoundInZip = 'File not found in ZIP content: %s'; 

// ZIP file format records. 
// The generic zip file format is (TLocalFileHeader; Name; Extra; compressed data)* (TFileHeader; Name; Extra; Remark)* TLastHeader 

type 
    TFileInfo = packed record 
    NeededVersion:      Word;   // 20 
    Flags:        Word;   // 1=Text,4=extra present 
    ZipMethod:       Word;   // 0=stored 8=deflate 
    LastModified:      Longword;  // time in dos format or Unix Timestamp 
    Crc32:        Longword; 
    CompressedSize:     Longword; 
    UncompressedSize:     Longword; 
    NameSize:       Word; 
    ExtraSize:       Word; 
    end; 

    TFileHeader = packed record 
    Signature:       Longword;  // $02014b50 PK#1#2 
    MadeBy:       Word;   // Version number, 20 
    FileInfo:       TFileInfo; 
    CommentSize:      Word;   // 0 
    FirstDiskNumber:     Word;   // 0 
    IntFileAttr:      Word;   // 0 = binary; 1 = text 
    ExtFileAttr:      Longword;  // DOS file attributes (Archived=32) 
    LocalFileHeaderHeadOff:   Longword;  // @TLocalFileHeader 
    end; 
    PFileHeader = ^TFileHeader; 

    TLocalFileHeader = packed record 
    Signature:       Longword;  // $02014b50 PK#3#4 
    FileInfo:       TFileInfo; 
    end; 
    PLocalFileHeader = ^TLocalFileHeader; 

    TLastHeader = packed record 
    Signature:       Longword;  // $02014b50 PK#5#6 
    ThisDiskNumber:     Word; 
    CentralDirDisk:     Word; 
    ThisDiskFileCount:     Word; 
    TotalFileCount:     Word; 
    FileHeaderSize:     Longword; 
    FileHeaderOffset:     Longword; 
    CommentSize:      Word; 
    end; 
    PLastHeader = ^TLastHeader; 

const 
    MagicLastHeader = $06054b50; 
    MagicLocalHeader = $04034b50; 
    MagicFileHeader = $02014b50; 

type 
    IntPtr = Longword; // NativeInt on Delphi2007 is an Int64 ?? 

{$if CompilerVersion < 19} 
procedure SetAnsiString(var S: AnsiString; P: PAnsiChar; L: Integer); inline; 
begin 
    SetString(S, P, L); 
end; 
{$ifend} 

{ TZipFileReader } 

constructor TZipFileReader.Create(const FileName: string; ZipStartOffset: Int64; Size: Longword); 
begin 
    // Open the file in question. 
    FFileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0); 
    if FFileHandle = INVALID_HANDLE_VALUE then raise EZipException.CreateFmt(cCannotOpenFile, [ Filename, GetLastError() ]); 
    if Size = 0 then Size := GetFileSize(FFileHandle, nil); 
    if Size = INVALID_FILE_SIZE then raise EZipException.CreateFmt(cCannotGetFileSize, [ Filename, GetLastError() ]); 

    try 
    // Create a file mapping of the file in question 
    FFileMapping := CreateFileMapping(FFileHandle, nil, PAGE_READONLY, 0, 0, nil); 
    if FFileMapping = 0 then raise EZipException.CreateFmt(cCannotMapFile, [ Filename, GetLastError() ]); 

    try 
     // Get the file mapped in memory (NOTE: The offset needs to be on the memory allocation granularity of the system) 
     // Hence we assign it it's own pointer -> todo rounding etc. 
     FMappedAddress := MapViewOfFile(FFileMapping, FILE_MAP_READ, Int64Rec(ZipStartOffset).Hi, Int64Rec(ZipStartOffset).Lo, Size); 
     if not Assigned(FMappedAddress) then EZipException.CreateFmt(cCannotMapFile, [ Filename, GetLastError() ]); 
     Create(FMappedAddress, Size); 
    except 
     CloseHandle(FFileMapping); 
     FFileMapping := 0; 
     raise; 
    end; 
    except 
    CloseHandle(FFileHandle); 
    FFileHandle := 0; 
    raise; 
    end; 
end; 

constructor TZipFileReader.Create(const ResourceName, ResourceType: string; Instance: HMODULE); 
var 
    Resource: HRSRC; 
    Global: HGLOBAL; 
begin 
    Resource := FindResource(Instance, PChar(ResourceName), PChar(ResourceType)); 
    if Resource = 0 then raise EZipException.CreateFmt(cResourceNotFound, [ ResourceName, ResourceType ]); 
    Global := LoadResource(Instance, Resource); 
    if Global = 0 then raise EZipException.CreateFmt(cResourceNotLoaded, [ ResourceName, ResourceType ]); 
    Create(LockResource(Global), SizeofResource(HInstance, Resource)); 
    // Note: kb57808: SizeofResource() returns the resource size rounded up to the alignment size. 
end; 

constructor TZipFileReader.Create(Buffer: Pointer; Size: Longword); 
var 
    LastHeader: PLastHeader; 
    FileHeader: PFileHeader; 
    i, Off:  Longword; 
    Name:  AnsiString; 
begin 
    // Note the location. 
    FStart := Buffer; 
    FSize := Size; 

    // Some sanity checks. 
    if FSize < sizeof(TLocalFileHeader) + sizeof(TFileHeader) + sizeof(TLastHeader) then raise EZipException.Create(cZipFileTooSmall); 
    if IsBadReadPtr(Buffer, Size) then raise EZipException.Create(cZipBufferInvalid); 
    if PLongword(Buffer)^ <> MagicLocalHeader then raise EZipException.Create(cZipFileFormatError); 

    // Find the last header. Due to the alignment of SizeofResource, we need o search for it. 
    LastHeader := Pointer(IntPtr(Buffer) + Size - sizeof(TLastHeader)); 
    for i := 0 to 31 do begin 
    if LastHeader^.Signature = MagicLastHeader then Break; 
    Dec(IntPtr(LastHeader)); 
    end; 
    if LastHeader^.Signature <> MagicLastHeader then raise EZipException.Create(cZipFileFormatError); 

    FFilenames := TStringList.Create(); 

    Off := LastHeader^.FileHeaderOffset; 
    for i := 0 to LastHeader^.TotalFileCount - 1 do begin 
    // Get header 
    if Off + sizeof(TFileHeader) >= Size then raise EZipException.Create(cZipFileFormatError); 
    FileHeader := Pointer(IntPtr(Buffer) + Off); 
    Inc(Off, sizeof(TFileHeader)); 
    if FileHeader^.Signature <> MagicFileHeader then raise EZipException.Create(cZipFileFormatError); 

    // Get filename 
    if Off + FileHeader^.FileInfo.NameSize + FileHeader^.FileInfo.ExtraSize >= Size then raise EZipException.Create(cZipFileFormatError); 
    SetAnsiString(Name, Pointer(IntPtr(Buffer) + Off), FileHeader^.FileInfo.NameSize); 
    Inc(Off, FileHeader^.FileInfo.NameSize + FileHeader^.FileInfo.ExtraSize); 

    // Save filename and offset into ZIPfile where it can be found. 
    FFileNames.AddObject(Name, Pointer(FileHeader^.LocalFileHeaderHeadOff)); 
    end; 
    // For quick access. 
    TStringList(FFilenames).Sorted := True; 

end; 

destructor TZipFileReader.Destroy; 
begin 
    if Assigned(FMappedAddress) then UnmapViewOfFile(FMappedAddress); 
    if FFileMapping <> 0 then CloseHandle(FFileMapping); 
    if FFileHandle <> 0 then CloseHandle(FFileHandle ); 
    inherited Destroy; 
end; 

function TZipFileReader.GetFile(const FileName: string): TBytes; 
var 
    ID: Integer; 
begin 
    // Convert filename in FileID and access by ID. 
    ID := FFilenames.IndexOf(FileName); 
    if ID < 0 then raise EZipException.CreateFmt(cFileNotFoundInZip, [ FileName ]); 
    Result := GetFile(ID); 
end; 

function TZipFileReader.GetFile(FileID: Integer): TBytes; 
var 
    Off: Longword; 
    Local: PLocalFileHeader; 
    ZRec: TZStreamRec; 
const 
    ZLibHeader: array [ 0..1 ] of Byte = ($78, $01); // Deflate 32KB window size no preset dictionary. 
begin 
    // Sanity check 
    if (FileID < 0) or (FileID >= FFilenames.Count) then raise EZipException.CreateFmt('Invalid File ID: %d', [ FileID ]); 

    // Get the file header and perform sanity check 
    Off := Longword(FFilenames.Objects[ FileID ]); 
    if Off + sizeof(TLocalFileHeader) >= FSize then raise EZipException.Create(cZipFileFormatError); 
    Local := Pointer(IntPtr(FStart) + Off); 
    if Local^.Signature <> MagicLocalHeader then raise EZipException.Create(cZipFileFormatError); 
    Inc(Off, sizeof(TLocalFileHeader) + Local^.FileInfo.NameSize + Local^.FileInfo.ExtraSize); 
    if Off + Local^.FileInfo.CompressedSize >= FSize then raise EZipException.Create(cZipFileFormatError); 
    // note: should we check the name again? 

    SetLength(Result, Local^.FileInfo.UncompressedSize); 
    if Length(Result) > 0 then case Local^.FileInfo.ZipMethod of 
    0: begin // STORED 
      if Local^.FileInfo.CompressedSize <> Local^.FileInfo.UncompressedSize then raise EZipException.Create(cZipFileFormatError); 
      Move(Pointer(IntPtr(FStart) + Off)^, Result[ 0 ], Local^.FileInfo.UncompressedSize); 
     end; 
    8: begin // DEFLATE 
      ZeroMemory(@ZRec, sizeof(ZRec)); 
      ZRec.next_in := @ZLibHeader; 
      ZRec.avail_in := sizeof(ZLibHeader); 
      ZRec.total_in := sizeof(ZLibHeader) + Local^.FileInfo.CompressedSize; 
      ZRec.next_out := @Result[ 0 ]; 
      ZRec.avail_out := Local^.FileInfo.UncompressedSize; 
      ZRec.total_out := Local^.FileInfo.UncompressedSize; 
      ZRec.zalloc := zlibAllocMem; 
      ZRec.zfree  := zlibFreeMem; 
      if inflateInit_(ZRec, zlib_Version, sizeof(ZRec)) <> 0 then raise EZipException.Create(cZipFileFormatError); 
      try 
      if not(inflate(ZRec, Z_FULL_FLUSH) in [ Z_OK, Z_STREAM_END ]) then raise EZipException.Create(cZipFileFormatError); 
      ZRec.next_in := Pointer(IntPtr(FStart) + Off); 
      ZRec.avail_in := Local^.FileInfo.CompressedSize; 
      if not(inflate(ZRec, Z_FINISH) in [ Z_OK, Z_STREAM_END ]) then raise EZipException.Create(cZipFileFormatError); 
      finally 
      inflateEnd(ZRec); 
      end; 
     end; 
    else raise EZipException.CreateFmt(cUnsupportedMethod, [ Local^.FileInfo.ZipMethod ]); 
    end; 

    // todo: CRC32 sanity check if requested. 
end; 

function TZipFileReader.GetZipFileInfo(const FileName: AnsiString): TZipFileInfo; 
var 
    FileID: Integer; 
    Off: Longword; 
    Local: PLocalFileHeader; 
begin 
    // Get the correct file ID 
    FileID := FFilenames.IndexOf(FileName); 
    if FileID < 0 then raise EZipException.CreateFmt(cFileNotFoundInZip, [ FileName ]); 

    // Get the file header and perform sanity check 
    Off := Longword(FFilenames.Objects[ FileID ]); 
    if Off + sizeof(TLocalFileHeader) >= FSize then raise EZipException.Create(cZipFileFormatError); 
    Local := Pointer(IntPtr(FStart) + Off); 
    if Local^.Signature <> MagicLocalHeader then raise EZipException.Create(cZipFileFormatError); 
    Inc(Off, sizeof(TLocalFileHeader) + Local^.FileInfo.NameSize + Local^.FileInfo.ExtraSize); 
    if Off + Local^.FileInfo.CompressedSize >= FSize then raise EZipException.Create(cZipFileFormatError); 

    // Return requested data. 
    Result.LastModified  := Local^.FileInfo.LastModified; 
    Result.Crc32   := Local^.FileInfo.Crc32; 
    Result.CompressedSize := Local^.FileInfo.CompressedSize; 
    Result.UncompressedSize := Local^.FileInfo.UncompressedSize; 
end; 

end. 
2

Jetez un oeil à ce OpenSource SynZip unit. Il est encore plus rapide pour la décompression que l'unité par défaut livré avec Delphi, et il va générer une plus petite exe (tables crc sont créés au démarrage).

Aucun dll externe est nécessaire.

Je viens de faire quelques changements pour gérer les noms de fichiers Unicode à l'intérieur du contenu Zip, non seulement Win-Ansi charset mais CARactère Unicode. Les commentaires sont les bienvenus.

Questions connexes