2009-11-20 2 views
8

Знаете ли вы какой-либо бесплатный компонент, совместимый с Delphi или XE для управления ZIP-архивами (на самом деле, только чтение содержимого архива и извлечение необходимых файлов)?Бесплатный компонент ZIP для Delphi 2010/Delphi XE?

Пожалуйста, не бета-версии.

Я думал о ZipForge от ComponentAce, но это бесплатно только для личного пользования. Разрешено распространение программного обеспечения.

+0

Вам нужно только кодирование/декодирование или и то, и другое? –

+0

@ Ritsaert Hornstra Ну, и я верю. –

+1

Примечание: Добавлена ​​поддержка файлов ZIP для Delphi XE2: [http://docwiki.embarcadero.com/Libraries/Seattle/en/System.Zip.TZipFile.ExtractAll] [http: // delphiblog.twodesk.com/native-zip-file-support-in-delphi-xe2] Потребовалось некоторое время! – Ampere

ответ

16

Вы можете получить TurboPower Abbrevia за 2010 год от: http://tpabbrevia.sourceforge.net/

+0

TurboPower Abbrevia сжатия \t данных \t 9 сентября 2008 Это, кажется, не быть не тестировался обновлялись Delphi 2010 :( –

+2

Я обновил URL, так как версия Abbrevia на SourceForge не поддерживает Delphi 2010/XE и имеет модульные тесты. –

4

вы посмотрите на this может, если Вам нравится 7zip

+1

Там в немного информации, отсутствующей на этой странице. Есть эта ссылка: http://www.7-zip.org/sdk.html, но это не обрабатывает API до 7z.dll, и я читаю, что есть 7za.dll, что имеет COM-интерфейс (другими словами: имеет библиотеку типов для импорта) –

+0

Да, это многообещающе. Спасибо! –

+0

Я принимаю этот ответ. Это просто интересно и полезно для меня. Спасибо. –

1

Мне нравится совместимую TZipMaster WinZip для Delphi, доступны здесь: http://www.delphizip.org/

TZipMaster является невизуальным VCL оберткой созданного ChrisVleghert и EricW.Engler для их бесплатной Zip и распаковать DLL.

Эти библиотеки DLL основаны на InfoZip Official Freeware Zip/источник Распакуйте кода, но не эквивалентны библиотек DLL InfoZip в. Исходный код InfoZip был изменен для улучшения их простоты использования, мощности и гибкости для использования с Delphi и C++ Builder.

Кроме того, у этого вопроса есть been covered before на переполнение стека, что может дать некоторые другие решения для вас.

+0

TZipMaster (до версии v1. 79) не удалось успешно построить в D2009. Хотя это версия 1.79 будет работать в среде Unicode, она все еще имеет те же ограничения, что и предыдущие версии. Он не совместим с D2010 также или не тестировался. –

+0

ZipMaster теперь совместим, по крайней мере, я вижу исправления в новостях. Спасибо за предложение! –

0

DotNetZip - это библиотека управляемого кода (.NET), которая предоставляет COM-интерфейс.

Бесплатно.
Открытый исходный код
MS-PL имеет лицензию.

+1

Неверная платформа и слишком много накладных расходов для приложения Delphi. –

1

Если распространение DLL ActiveX с вашим проектом не является проблемой для вас, то Chilkat Zip (http://www.chilkatsoft.com/zip-activex.asp), похоже, делает трюк. примеры Delphi здесь: http://www.example-code.com/delphi/zip.asp

3

Если требуется только декодирование (разработанный для Delphi 2007, но не тестировалось под 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

Взгляните на эту OpenSource SynZip unit. Это даже быстрее для декомпрессии, чем блок по умолчанию, поставляемый с Delphi, и он будет генерировать меньший exe (таблицы crc создаются при запуске).

Внешняя dll не требуется.

Я только что ввел некоторые изменения, чтобы обрабатывать имена файлов Unicode внутри содержимого Zip, а не только кодировку Win-Ansi, но любые символы Unicode. Обратная связь приветствуется.

Смежные вопросы