<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_万一的 Delphi 博客</title><subtitle type="text">记录学习过程中的点点滴滴，是喜欢、不是职业；记性不好，特别需要这么一个博客。</subtitle><id>http://feed.cnblogs.com/blog/u/30694/rss</id><updated>2012-02-06T06:59:48Z</updated><author><name>万一</name><uri>http://www.cnblogs.com/del/</uri></author><generator>CNBlogs BlogServer</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/del/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/30694/rss"/><entry><id>http://www.cnblogs.com/del/archive/2012/02/04/2337938.html</id><title type="text">给 System.Zip 增加了个(多文件解压时的)解压进度事件</title><summary type="text">很喜欢 System.Zip; 手头的程序需要把压缩后的一组文件从内存流解压, 这用 System.Zip 非常简单, 但我需要呈现解压进度, 同时给出当前文件名.因此给 System.Zip.TZipFile 添加了一个 OnUnZipProgress 事件.在 System.Zip 的基础上添加了不足 10 行代码, 新加代码都在行尾标记了 ///.修改后的文件(Zip2.pas):unit Zip2;interfaceuses System.SysUtils, System.IOUtils, System.Generics.Collections, System.Classes;...</summary><published>2012-02-04T05:51:00Z</published><updated>2012-02-04T05:51:00Z</updated><author><name>万一</name><uri>http://www.cnblogs.com/del/</uri></author><link rel="alternate" href="http://www.cnblogs.com/del/archive/2012/02/04/2337938.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/del/archive/2012/02/04/2337938.html"/><content type="html">&lt;br/&gt;&#xD;
很喜欢 System.Zip; 手头的程序需要把压缩后的一组文件从内存流解压, 这用 System.Zip 非常简单, 但我需要呈现解压进度, 同时给出当前文件名.&lt;br/&gt;&lt;br/&gt;&#xD;
&#xD;
因此给 System.Zip.TZipFile 添加了一个 OnUnZipProgress 事件.&lt;br/&gt;&lt;br/&gt;&#xD;
&#xD;
在 System.Zip 的基础上添加了不足 10 行代码, 新加代码都在行尾标记了 ///.&lt;hr/&gt;&lt;br/&gt;&#xD;
&#xD;
修改后的文件(Zip2.pas):&lt;hr/&gt;&#xD;
&lt;br/&gt;&lt;pre &gt;unit Zip2;&#xD;
&#xD;
interface&#xD;
&#xD;
uses&#xD;
  System.SysUtils,&#xD;
  System.IOUtils,&#xD;
  System.Generics.Collections,&#xD;
  System.Classes;&#xD;
&#xD;
type&#xD;
  TZipCompression = (&#xD;
    zcStored    = 0,&#xD;
    zcShrunk,&#xD;
    zcReduce1,&#xD;
    zcReduce2,&#xD;
    zcReduce3,&#xD;
    zcReduce4,&#xD;
    zcImplode,&#xD;
    zcTokenize,&#xD;
    zcDeflate,&#xD;
    zcDeflate64,&#xD;
    zcPKImplode,&#xD;
    {11 RESERVED}&#xD;
    zcBZIP2    = 12,&#xD;
    {13 RESERVED}&#xD;
    zcLZMA     = 14,&#xD;
    {15-17 RESERVED}&#xD;
    zcTERSE    = 18,&#xD;
    zcLZ77,&#xD;
    zcWavePack = 97,&#xD;
    zcPPMdI1&#xD;
  );&#xD;
&#xD;
function TZipCompressionToString(Compression: TZipCompression): string;&#xD;
const&#xD;
  SIGNATURE_ZIPENDOFHEADER: UInt32 = $06054B50;&#xD;
  SIGNATURE_CENTRALHEADER:  UInt32 = $02014B50;&#xD;
  SIGNATURE_LOCALHEADER:    UInt32 = $04034B50;&#xD;
&#xD;
  LOCALHEADERSIZE = 26;&#xD;
  CENTRALHEADERSIZE = 42;&#xD;
&#xD;
type&#xD;
  TZipEndOfCentralHeader = packed record&#xD;
    DiskNumber:          UInt16;&#xD;
    CentralDirStartDisk: UInt16;&#xD;
    NumEntriesThisDisk:  UInt16;&#xD;
    CentralDirEntries:   UInt16;&#xD;
    CentralDirSize:      UInt32;&#xD;
    CentralDirOffset:    UInt32;&#xD;
    CommentLength:       UInt16;&#xD;
  end;&#xD;
&#xD;
  TZipHeader = packed record&#xD;
    MadeByVersion:      UInt16;&#xD;
    RequiredVersion:    UInt16;&#xD;
    Flag:               UInt16;&#xD;
    CompressionMethod:  UInt16;&#xD;
    ModifiedDateTime:   UInt32;&#xD;
    CRC32:              UInt32;&#xD;
    CompressedSize:     UInt32;&#xD;
    UncompressedSize:   UInt32;&#xD;
    FileNameLength:     UInt16;&#xD;
    ExtraFieldLength:   UInt16;&#xD;
    FileCommentLength:  UInt16;&#xD;
    DiskNumberStart:    UInt16;&#xD;
    InternalAttributes: UInt16;&#xD;
    ExternalAttributes: UInt32;&#xD;
    LocalHeaderOffset:  UInt32;&#xD;
    FileName: RawByteString;&#xD;
    ExtraField: TBytes;&#xD;
    FileComment: RawByteString;&#xD;
  end;&#xD;
  PZipHeader = ^TZipHeader;&#xD;
&#xD;
  EZipException = class( Exception );&#xD;
&#xD;
  TZipMode = (zmClosed, zmRead, zmReadWrite, zmWrite);&#xD;
&#xD;
  TZipFile = class;&#xD;
&#xD;
  TStreamConstructor = reference to function(InStream: TStream; const ZipFile: TZipFile; const Item: TZipHeader): TStream;&#xD;
&#xD;
  TUnZipProgressEvent = procedure(Sender: TObject; ACount,AIndex: Integer; AFileName: string) of object; ///&#xD;
&#xD;
  TZipFile = class&#xD;
  private type&#xD;
    TCompressionDict = TDictionary&amp;lt; TZipCompression , TPair&amp;lt;TStreamConstructor, TStreamConstructor &amp;gt; &amp;gt;;&#xD;
  private class var&#xD;
    FCompressionHandler: TCompressionDict;&#xD;
  private&#xD;
    FMode: TZipMode;&#xD;
    FStream: TStream;&#xD;
    FFileStream: TFileStream;&#xD;
    FStartFileData: Int64;&#xD;
    FEndFileData: Int64;&#xD;
    FFiles: TList&amp;lt;TZipHeader&amp;gt;;&#xD;
    FComment: String;&#xD;
    FUTF8Support: Boolean;&#xD;
    function GetFileComment(Index: Integer): string;&#xD;
    function GetFileCount: Integer;&#xD;
    function GetFileInfo(Index: Integer): TZipHeader;&#xD;
    function GetFileInfos: TArray&amp;lt;TZipHeader&amp;gt;;&#xD;
    function GetFileName(Index: Integer): string;&#xD;
    function GetFileNames: TArray&amp;lt;string&amp;gt;;&#xD;
    procedure ReadCentralHeader;&#xD;
    procedure SetFileComment(Index: Integer; Value: string);&#xD;
    procedure SetUTF8Support(const Value: Boolean);&#xD;
    function LocateEndOfCentralHeader(var Header: TZipEndOfCentralHeader): Boolean;&#xD;
  protected                                                                ///&#xD;
    FOnUnZipProgress: TUnZipProgressEvent;                                 ///&#xD;
    procedure DoUnZipProgress(ACount,AIndex: Integer; AFileName: string);  ///&#xD;
  public&#xD;
    class constructor Create;&#xD;
    class destructor Destroy;&#xD;
    class procedure RegisterCompressionHandler(Compression: TZipCompression;&#xD;
      CompressStream, DecompressStream: TStreamConstructor);&#xD;
    class function IsValid(ZipFileName: string): Boolean; static;&#xD;
    class procedure ExtractZipFile(ZipFileName: string; Path: string); static;&#xD;
    class procedure ZipDirectoryContents(ZipFileName: string; Path: string;&#xD;
      Compression: TZipCompression = zcDeflate); static;&#xD;
    constructor Create;&#xD;
    destructor Destroy; override;&#xD;
    procedure Open(ZipFileName: string; OpenMode: TZipMode); overload;&#xD;
    procedure Open(ZipFileStream: TStream; OpenMode: TZipMode); overload;&#xD;
    procedure Close;&#xD;
    procedure Extract(FileName: string; Path: string = ''; CreateSubdirs: Boolean=True); overload;&#xD;
    procedure Extract(Index: Integer; Path: string = ''; CreateSubdirs: Boolean=True); overload;&#xD;
    procedure ExtractAll(Path: string = '');&#xD;
    procedure Read(FileName: string; out Bytes: TBytes); overload;&#xD;
    procedure Read(Index: Integer; out Bytes: TBytes); overload;&#xD;
    procedure Read(FileName: string; out Stream: TStream; out LocalHeader: TZipHeader); overload;&#xD;
    procedure Read(Index: Integer; out Stream: TStream; out LocalHeader: TZipHeader); overload;&#xD;
    procedure Add(FileName: string; ArchiveFileName: string = '';&#xD;
      Compression: TZipCompression = zcDeflate); overload;&#xD;
    procedure Add(Data: TBytes; ArchiveFileName: string;&#xD;
      Compression: TZipCompression = zcDeflate); overload;&#xD;
    procedure Add(Data: TStream; ArchiveFileName: string;&#xD;
      Compression: TZipCompression = zcDeflate); overload;&#xD;
    procedure Add(Data: TStream; LocalHeader: TZipHeader;&#xD;
      CentralHeader: PZipHeader = nil); overload;&#xD;
    function IndexOf(FileName: string): Integer;&#xD;
    property Mode: TZipMode read FMode;&#xD;
    property FileCount: Integer read GetFileCount;&#xD;
    property FileNames: TArray&amp;lt;string&amp;gt; read GetFileNames;&#xD;
    property FileInfos: TArray&amp;lt;TZipHeader&amp;gt; read GetFileInfos;&#xD;
    property FileName[Index: Integer]: string read GetFileName;&#xD;
    property FileInfo[Index: Integer]: TZipHeader read GetFileInfo;&#xD;
    property FileComment[Index: Integer]: string read GetFileComment write SetFileComment;&#xD;
    property Comment: string read FComment write FComment;&#xD;
    property UTF8Support: Boolean read FUTF8Support write SetUTF8Support default True;&#xD;
    property OnUnZipProgress: TUnZipProgressEvent read FOnUnZipProgress write FOnUnZipProgress; ///&#xD;
  end;&#xD;
&#xD;
implementation&#xD;
&#xD;
uses&#xD;
  System.RTLConsts,&#xD;
  System.ZLib;&#xD;
&#xD;
type&#xD;
  TOem437String = type AnsiString(437);&#xD;
&#xD;
procedure VerifyRead(Stream: TStream; var Buffer; Count: Integer);&#xD;
begin&#xD;
  if Stream.Read(Buffer, Count) &amp;lt;&amp;gt; Count then&#xD;
  raise EZipException.CreateRes(@SZipErrorRead) at ReturnAddress;&#xD;
end;&#xD;
&#xD;
procedure VerifyWrite(Stream: TStream; var Buffer; Count: Integer);&#xD;
begin&#xD;
  if Stream.Write(Buffer, Count) &amp;lt;&amp;gt; Count then&#xD;
    raise EZipException.CreateRes(@SZipErrorWrite) at ReturnAddress;&#xD;
end;&#xD;
&#xD;
type&#xD;
  TStoredStream = class( TStream )&#xD;
  private&#xD;
    FStream: TStream;&#xD;
    FPos: Int64;&#xD;
  protected&#xD;
    function GetSize: Int64; override;&#xD;
  public&#xD;
    constructor Create( Stream: TStream );&#xD;
    function Read(var Buffer; Count: Longint): Longint; override;&#xD;
    function Write(const Buffer; Count: Longint): Longint; override;&#xD;
    function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;&#xD;
  end;&#xD;
&#xD;
{ TStoredStream }&#xD;
&#xD;
constructor TStoredStream.Create(Stream: TStream);&#xD;
begin&#xD;
  FStream := Stream;&#xD;
  FPos := FStream.Position;&#xD;
end;&#xD;
&#xD;
function TStoredStream.GetSize: Int64;&#xD;
begin&#xD;
  Result := FStream.Size;&#xD;
end;&#xD;
&#xD;
function TStoredStream.Read(var Buffer; Count: Integer): Longint;&#xD;
begin&#xD;
  Result := FStream.Read(Buffer, Count);&#xD;
end;&#xD;
&#xD;
function TStoredStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;&#xD;
begin&#xD;
  Result := FStream.Seek(Offset, Origin)&#xD;
end;&#xD;
&#xD;
function TStoredStream.Write(const Buffer; Count: Integer): Longint;&#xD;
begin&#xD;
  Result := FStream.Write(Buffer, Count);&#xD;
end;&#xD;
&#xD;
function TZipCompressionToString(Compression: TZipCompression): string;&#xD;
begin&#xD;
  case Compression of&#xD;
    zcStored:    Result := 'Stored';&#xD;
    zcShrunk:    Result := 'Shrunk';&#xD;
    zcReduce1:   Result := 'Reduced1';&#xD;
    zcReduce2:   Result := 'Reduced2';&#xD;
    zcReduce3:   Result := 'Reduced3';&#xD;
    zcReduce4:   Result := 'Reduced4';&#xD;
    zcImplode:   Result := 'Imploded';&#xD;
    zcTokenize:  Result := 'Tokenized';&#xD;
    zcDeflate:   Result := 'Deflated';&#xD;
    zcDeflate64: Result := 'Deflated64';&#xD;
    zcPKImplode: Result := 'Imploded(TERSE)';&#xD;
    zcBZIP2:     Result := 'BZIP2';&#xD;
    zcLZMA:      Result := 'LZMA';&#xD;
    zcTERSE:     Result := 'TERSE';&#xD;
    zcLZ77:      Result := 'LZ77';&#xD;
    zcWavePack:  Result := 'WavPack';&#xD;
    zcPPMdI1:    Result := 'PPMd version I, Rev 1';&#xD;
    else&#xD;
      Result := 'Unknown';&#xD;
  end;&#xD;
end;&#xD;
&#xD;
{ TZipFile }&#xD;
&#xD;
function TZipFile.GetFileComment(Index: Integer): string;&#xD;
begin&#xD;
  if FMode = zmClosed then&#xD;
    raise EZipException.CreateRes(@SZipNotOpen);&#xD;
  Result := string(FFiles[Index].FileComment);&#xD;
end;&#xD;
&#xD;
function TZipFile.GetFileCount: Integer;&#xD;
begin&#xD;
  if FMode = zmClosed then&#xD;
    raise EZipException.CreateRes(@SZipNotOpen);&#xD;
  Result := FFiles.Count;&#xD;
end;&#xD;
&#xD;
function TZipFile.GetFileInfo(Index: Integer): TZipHeader;&#xD;
begin&#xD;
  if FMode = zmClosed then&#xD;
    raise EZipException.CreateRes(@SZipNotOpen);&#xD;
  Result := FFiles[Index];&#xD;
end;&#xD;
&#xD;
function TZipFile.GetFileInfos: TArray&amp;lt;TZipHeader&amp;gt;;&#xD;
begin&#xD;
  if FMode = zmClosed then&#xD;
    raise EZipException.CreateRes(@SZipNotOpen);&#xD;
  Result := FFiles.ToArray;&#xD;
end;&#xD;
&#xD;
function TZipFile.GetFileName(Index: Integer): string;&#xD;
begin&#xD;
  if FMode = zmClosed then&#xD;
    raise EZipException.CreateRes(@SZipNotOpen);&#xD;
  Result := string(FFiles[Index].FileName);&#xD;
end;&#xD;
&#xD;
function TZipFile.GetFileNames: TArray&amp;lt;string&amp;gt;;&#xD;
var&#xD;
  I: Integer;&#xD;
begin&#xD;
  if FMode = zmClosed then&#xD;
    raise EZipException.CreateRes(@SZipNotOpen);&#xD;
  SetLength(Result, FFiles.Count);&#xD;
  for I := 0 to High(Result) do&#xD;
    Result[I] := string(FFiles[I].FileName);&#xD;
end;&#xD;
&#xD;
procedure TZipFile.ReadCentralHeader;&#xD;
var&#xD;
  I: Integer;&#xD;
  Signature: UInt32;&#xD;
  LEndHeader: TZipEndOfCentralHeader;&#xD;
  LHeader: TZipHeader;&#xD;
begin&#xD;
  FFiles.Clear;&#xD;
  if FStream.Size = 0 then&#xD;
    Exit;&#xD;
  if not LocateEndOfCentralHeader(LEndHeader) then&#xD;
    raise EZipException.CreateRes(@SZipErrorRead);&#xD;
  FStream.Position := LEndHeader.CentralDirOffset;&#xD;
  FEndFileData := LEndHeader.CentralDirOffset;&#xD;
  for I := 0 to LEndHeader.CentralDirEntries - 1 do&#xD;
  begin&#xD;
    FStream.Read(Signature, Sizeof(Signature));&#xD;
    if Signature &amp;lt;&amp;gt; SIGNATURE_CENTRALHEADER then&#xD;
      raise EZipException.CreateRes(@SZipInvalidCentralHeader);&#xD;
    VerifyRead(FStream, LHeader.MadeByVersion, CENTRALHEADERSIZE);&#xD;
    if LHeader.FileNameLength &amp;gt; 0 then&#xD;
    begin&#xD;
      SetLength(LHeader.FileName, LHeader.FileNameLength);&#xD;
      if (LHeader.Flag and (1 SHL 11)) &amp;lt;&amp;gt; 0 then&#xD;
        SetCodepage(LHeader.FileName, 65001, False)&#xD;
      else&#xD;
        SetCodepage(LHeader.FileName, 437, False);&#xD;
      VerifyRead(FStream, LHeader.FileName[1], LHeader.FileNameLength);&#xD;
    end;&#xD;
    if LHeader.ExtraFieldLength &amp;gt; 0 then&#xD;
    begin&#xD;
      SetLength(LHeader.ExtraField, LHeader.ExtraFieldLength);&#xD;
      VerifyRead(FStream, LHeader.ExtraField[0], LHeader.ExtraFieldLength);&#xD;
    end;&#xD;
    if LHeader.FileCommentLength &amp;gt; 0 then&#xD;
    begin&#xD;
      SetLength(LHeader.FileComment, LHeader.FileCommentLength);&#xD;
      if (LHeader.Flag and (1 SHL 11)) &amp;lt;&amp;gt; 0 then&#xD;
        SetCodepage(LHeader.FileName, 65001, False)&#xD;
      else&#xD;
        SetCodepage(LHeader.FileName, 437, False);&#xD;
      VerifyRead(FStream, LHeader.FileComment[1], LHeader.FileCommentLength);&#xD;
    end;&#xD;
    if (LHeader.Flag and (1 shl 11)) = 0 then&#xD;
      FUTF8Support := False;&#xD;
&#xD;
    FFiles.Add(LHeader);&#xD;
  end;&#xD;
end;&#xD;
&#xD;
procedure TZipFile.SetFileComment(Index: Integer; Value: string);&#xD;
var&#xD;
  LFile: TZipHeader;&#xD;
begin&#xD;
  if not (FMode in [zmReadWrite, zmWrite]) then&#xD;
    raise EZipException.CreateRes(@SZipNoWrite);&#xD;
  LFile := FFiles[Index];&#xD;
  if Length(Value) &amp;gt; $FFFF then&#xD;
    SetLength(Value, $FFFF);&#xD;
  if UTF8Support then&#xD;
    LFile.FileComment := UTF8Encode(Value)&#xD;
  else&#xD;
    LFile.FileComment := TOem437String(Value);&#xD;
&#xD;
  LFile.FileCommentLength := Length(LFile.FileComment);&#xD;
  FFiles[Index] := LFile;&#xD;
end;&#xD;
&#xD;
procedure TZipFile.SetUTF8Support(const Value: Boolean);&#xD;
begin&#xD;
  if Value = FUTF8Support then Exit;&#xD;
  if not (FMode in [zmReadWrite, zmWrite]) then&#xD;
    raise EZipException.CreateRes(@SZipNoWrite);&#xD;
  if FFiles.Count &amp;lt;&amp;gt; 0 then&#xD;
    raise EZipException.CreateRes(@SZipNotEmpty);&#xD;
&#xD;
  FUTF8Support := Value;&#xD;
end;&#xD;
&#xD;
class constructor TZipFile.Create;&#xD;
begin&#xD;
  FCompressionHandler := TCompressionDict.Create;&#xD;
&#xD;
  RegisterCompressionHandler(zcStored,&#xD;
    function(InStream: TStream; const ZipFile: TZipFile; const Item: TZipHeader): TStream&#xD;
    begin&#xD;
      Result := TStoredStream.Create(InStream);&#xD;
    end,&#xD;
    function(InStream: TStream; const ZipFile: TZipFile; const Item: TZipHeader): TStream&#xD;
    begin&#xD;
      Result := TStoredStream.Create(InStream);&#xD;
    end);&#xD;
&#xD;
  RegisterCompressionHandler(zcDeflate,&#xD;
    function(InStream: TStream; const ZipFile: TZipFile; const Item: TZipHeader): TStream&#xD;
    begin&#xD;
      Result := TZCompressionStream.Create(InStream, zcDefault, -15);&#xD;
    end,&#xD;
    function(InStream: TStream; const ZipFile: TZipFile; const Item: TZipHeader): TStream&#xD;
    begin&#xD;
      Result := TZDecompressionStream.Create(InStream, -15);&#xD;
    end);&#xD;
end;&#xD;
&#xD;
class destructor TZipFile.Destroy;&#xD;
begin&#xD;
  FCompressionHandler.Free;&#xD;
end;&#xD;
&#xD;
class procedure TZipFile.RegisterCompressionHandler(&#xD;
  Compression: TZipCompression; CompressStream, DecompressStream: TStreamConstructor);&#xD;
begin&#xD;
  FCompressionHandler.AddOrSetValue(Compression,&#xD;
    TPair&amp;lt;TStreamConstructor, TStreamConstructor&amp;gt;.Create(CompressStream, DecompressStream));&#xD;
end;&#xD;
&#xD;
class function TZipFile.IsValid(ZipFileName: string): Boolean;&#xD;
var&#xD;
  Z: TZipFile;&#xD;
  Header: TZipEndOfCentralHeader;&#xD;
begin&#xD;
  Result := False;&#xD;
  try&#xD;
    Z := tzipfile.Create;&#xD;
    try&#xD;
      Z.FStream := TFileStream.Create(ZipFileName, fmOpenRead);&#xD;
      try&#xD;
        Result := Z.LocateEndOfCentralHeader(Header);&#xD;
      finally&#xD;
        Z.FStream.Free;&#xD;
      end;&#xD;
    finally&#xD;
      Z.Free;&#xD;
    end;&#xD;
  except on E: Exception do&#xD;
  end;&#xD;
end;&#xD;
&#xD;
function TZipFile.LocateEndOfCentralHeader(var Header: TZipEndOfCentralHeader): Boolean;&#xD;
var&#xD;
  I: Integer;&#xD;
  LBackRead, LReadSize, LMaxBack: UInt32;&#xD;
  LBackBuf: array[0..$404-1] of Byte;&#xD;
begin&#xD;
  if FStream.Size &amp;lt; $FFFF then&#xD;
    LMaxBack := FStream.Size&#xD;
  else&#xD;
    LMaxBack := $FFFF;&#xD;
  LBackRead := 4;&#xD;
  while LBackRead &amp;lt; LMaxBack do&#xD;
  begin&#xD;
    if LBackRead + Cardinal(Length(LBackBuf) - 4) &amp;gt; LMaxBack then&#xD;
      LBackRead := LMaxBack&#xD;
    else&#xD;
      Inc(LBackRead, Length(LBackBuf) -4);&#xD;
    FStream.Position := FStream.Size - LBackRead;&#xD;
    if Length(LBackBuf) &amp;lt; (FStream.Size - FStream.Position) then&#xD;
      LReadSize := Length(LBackBuf)&#xD;
    else&#xD;
      LReadSize := FStream.Size - FStream.Position;&#xD;
&#xD;
    VerifyRead(FStream, LBackBuf[0], LReadSize);&#xD;
&#xD;
    for I := LReadSize - 4 downto 0 do&#xD;
    begin&#xD;
      if PCardinal(@LBackBuf[I])^ = SIGNATURE_ZIPENDOFHEADER then&#xD;
      begin&#xD;
        Move(LBackBuf[I+4], Header, SizeOf(Header));&#xD;
        if Header.CommentLength &amp;gt; 0 then&#xD;
        begin&#xD;
          FStream.Position := FStream.Size - LBackRead + I + 4 + SizeOf(Header);&#xD;
          SetLength(FComment, Header.CommentLength);&#xD;
          FStream.Read(FComment[1], Header.CommentLength);&#xD;
        end&#xD;
        else&#xD;
          FComment := '';&#xD;
        Exit(True);&#xD;
      end;&#xD;
    end;&#xD;
  end;&#xD;
  Result := False;&#xD;
end;&#xD;
&#xD;
class procedure TZipFile.ExtractZipFile(ZipFileName: string; Path: string);&#xD;
var&#xD;
  LZip: TZipFile;&#xD;
begin&#xD;
  LZip := TZipFile.Create;&#xD;
  try&#xD;
    LZip.Open(ZipFileName, zmRead);&#xD;
    LZip.ExtractAll(Path);&#xD;
    LZip.Close;&#xD;
  finally&#xD;
    LZip.Free;&#xD;
  end;&#xD;
end;&#xD;
&#xD;
class procedure TZipFile.ZipDirectoryContents(ZipFileName: string; Path: string;&#xD;
  Compression: TZipCompression);&#xD;
var&#xD;
  LZipFile: TZipFile;&#xD;
  LFile: string;&#xD;
  LZFile: string;&#xD;
begin&#xD;
  LZipFile := TZipFile.Create;&#xD;
  try&#xD;
    LZipFile.Open(ZipFileName, zmWrite);&#xD;
    if Path[Length(Path)] &amp;lt;&amp;gt; PathDelim then&#xD;
      Path := Path + PathDelim;&#xD;
&#xD;
    for LFile in TDirectory.GetFiles(Path, '*', TSearchOption.soAllDirectories) do  &#xD;
    begin&#xD;
{$IFDEF MSWINDOWS}&#xD;
      LZFile := StringReplace(&#xD;
        Copy(LFile, Length(Path)+1, Length(LFile)), '\', '/', [rfReplaceAll]);&#xD;
{$ELSE}&#xD;
      LZFile := Copy(LFile, Length(Path)+1, Length(LFile));&#xD;
{$ENDIF MSWINDOWS}&#xD;
      LZipFile.Add(LFile, LZFile, Compression);&#xD;
    end;&#xD;
  finally&#xD;
    LZipFile.Free;&#xD;
  end;&#xD;
end;&#xD;
&#xD;
constructor TZipFile.Create;&#xD;
begin&#xD;
  inherited Create;&#xD;
  FFiles := TList&amp;lt;TZipHeader&amp;gt;.Create;&#xD;
  FMode := zmClosed;&#xD;
  FUTF8Support := True;&#xD;
end;&#xD;
&#xD;
destructor TZipFile.Destroy;&#xD;
begin&#xD;
  Close;&#xD;
  FFiles.Free;&#xD;
  inherited;&#xD;
end;&#xD;
&#xD;
procedure TZipFile.DoUnZipProgress(ACount, AIndex: Integer; AFileName: string); ///&#xD;
begin                                                                           ///&#xD;
  if Assigned(FOnUnZipProgress) then                                            ///&#xD;
    FOnUnZipProgress(Self, ACount, AIndex, AFileName);&#xD;
end;&#xD;
&#xD;
procedure TZipFile.Open(ZipFileName: string; OpenMode: TZipMode);&#xD;
var&#xD;
  LMode: LongInt;&#xD;
  LFileStream: TFileStream;&#xD;
begin&#xD;
  Close;&#xD;
  case OpenMode of&#xD;
    zmRead:      LMode := fmOpenRead;&#xD;
    zmReadWrite: LMode := fmOpenReadWrite;&#xD;
    zmWrite:     LMode := fmCreate;&#xD;
    else&#xD;
      raise EZipException.CreateRes(@sArgumentInvalid);&#xD;
  end;&#xD;
  LFileStream := TFileStream.Create(ZipFileName, LMode);&#xD;
  try&#xD;
    Open(LFileStream, OpenMode);&#xD;
    FFileStream := LFileStream;&#xD;
  except&#xD;
    FreeAndNil(LFileStream);&#xD;
    raise;&#xD;
  end;&#xD;
end;&#xD;
&#xD;
procedure TZipFile.Open(ZipFileStream: TStream; OpenMode: TZipMode);&#xD;
begin&#xD;
  Close;&#xD;
  if OpenMode = zmClosed then&#xD;
    raise EZipException.CreateRes(@sArgumentInvalid);&#xD;
  if (OpenMode = zmRead) and (ZipFileStream.Size = 0) then&#xD;
    raise EZipException.CreateRes(@SReadError);&#xD;
&#xD;
  FStream := ZipFileStream;&#xD;
  FStartFileData := FStream.Position;&#xD;
  if OpenMode in [zmRead, zmReadWrite] then&#xD;
  try&#xD;
    ReadCentralHeader;&#xD;
  except&#xD;
    FStream := nil;&#xD;
    raise;&#xD;
  end;&#xD;
  FMode := OpenMode;&#xD;
end;&#xD;
&#xD;
procedure TZipFile.Close;&#xD;
var&#xD;
  LHeader: TZipHeader;&#xD;
  LEndOfHeader: TZipEndOfCentralHeader;&#xD;
  I: Integer;&#xD;
  Signature: UInt32;&#xD;
begin&#xD;
  try&#xD;
    if (FMode = zmReadWrite) or (FMode = zmWrite) then&#xD;
    begin&#xD;
      FStream.Position := FEndFileData;&#xD;
      Signature := SIGNATURE_CENTRALHEADER;&#xD;
      for I := 0 to FFiles.Count - 1 do&#xD;
      begin&#xD;
        LHeader := FFiles[I];&#xD;
        VerifyWrite(FStream, Signature, SizeOf(Signature));&#xD;
        VerifyWrite(FStream, LHeader.MadeByVersion,  CENTRALHEADERSIZE);&#xD;
        if LHeader.FileNameLength &amp;lt;&amp;gt; 0 then&#xD;
          VerifyWrite(FStream, LHeader.FileName[1], LHeader.FileNameLength);&#xD;
        if LHeader.ExtraFieldLength &amp;lt;&amp;gt; 0 then&#xD;
          VerifyWrite(FStream, LHeader.ExtraField[1], LHeader.ExtraFieldLength);&#xD;
        if LHeader.FileCommentLength &amp;lt;&amp;gt; 0 then&#xD;
          VerifyWrite(FStream, LHeader.FileComment[1], LHeader.FileCommentLength);&#xD;
      end;&#xD;
      FillChar(LEndOfHeader, Sizeof(LEndOfHeader), 0);&#xD;
      LEndOfHeader.CentralDirEntries := FFiles.Count;&#xD;
      LEndOfHeader.NumEntriesThisDisk := FFiles.Count;&#xD;
      LEndOfHeader.CentralDirSize := FStream.Position - FEndFileData;&#xD;
      LEndOfHeader.CentralDirOffset := FEndFileData;&#xD;
      if Length(FComment) &amp;gt; $FFFF then&#xD;
        SetLength(FComment, $FFFF);&#xD;
      LEndofHeader.CommentLength := Length(FComment);&#xD;
      Signature := SIGNATURE_ZIPENDOFHEADER;&#xD;
      VerifyWrite(FStream, Signature, SizeOf(Signature));&#xD;
      VerifyWrite(FStream, LEndOfHeader, SizeOf(LEndOfHeader));&#xD;
      if LEndOfHeader.CommentLength &amp;gt; 0 then&#xD;
        VerifyWrite(FStream, FComment[1], LEndOfHeader.CommentLength);&#xD;
    end;&#xD;
  finally&#xD;
    FMode := zmClosed;&#xD;
    FFiles.Clear;&#xD;
    FStream := nil;&#xD;
    if Assigned(FFileStream) then&#xD;
      FreeAndNil(FFileStream);&#xD;
  end;&#xD;
end;&#xD;
&#xD;
procedure TZipFile.Extract(FileName: string; Path: string; CreateSubDirs: Boolean);&#xD;
begin&#xD;
  Extract(IndexOf(FileName), Path, CreateSubdirs);&#xD;
end;&#xD;
&#xD;
procedure TZipFile.Extract(Index: Integer; Path: string; CreateSubdirs: Boolean);&#xD;
var&#xD;
  LInStream, LOutStream: TStream;&#xD;
  LHeader: TZipHeader;&#xD;
  LDir, LFileName: string;&#xD;
  Bytes: array [0..4095] of Byte;&#xD;
  ReadBytes: Int64;&#xD;
begin&#xD;
  Read(Index, LInStream, LHeader);&#xD;
  try&#xD;
    LFileName := string(FFiles[Index].FileName);&#xD;
{$IFDEF MSWINDOWS}&#xD;
    LFileName := StringReplace(LFileName, '/', '\', [rfReplaceAll]);&#xD;
{$ENDIF}&#xD;
    if CreateSubdirs then&#xD;
      LFileName := TPath.Combine(Path, LFileName)&#xD;
    else&#xD;
      LFileName := TPath.Combine(Path, ExtractFileName(LFileName));&#xD;
    LDir := ExtractFileDir(LFileName);&#xD;
    if CreateSubdirs and (LDir &amp;lt;&amp;gt; '') then&#xD;
      TDirectory.CreateDirectory(ExtractFileDir(LFileName));&#xD;
    if LFileName[Length(LFileName)] = PathDelim then&#xD;
      Exit;&#xD;
    LOutStream := TFileStream.Create(LFileName, fmCreate);&#xD;
    try&#xD;
      if (LHeader.Flag and (1 SHL 3)) = 0 then&#xD;
        if FFiles[Index].UncompressedSize &amp;gt; 0 then&#xD;
          LOutStream.CopyFrom(LInStream, FFiles[Index].UncompressedSize)&#xD;
        else&#xD;
        begin&#xD;
          while True do&#xD;
          begin&#xD;
            ReadBytes := LInStream.Read(Bytes, Length(Bytes));&#xD;
            LOutStream.Write(Bytes, ReadBytes);&#xD;
            if ReadBytes &amp;lt; Length(Bytes) then&#xD;
              break;&#xD;
          end;&#xD;
        end;&#xD;
    finally&#xD;
      LOutStream.Free;&#xD;
    end;&#xD;
  finally&#xD;
    LInStream.Free;&#xD;
  end;&#xD;
end;&#xD;
&#xD;
procedure TZipFile.ExtractAll(Path: string);&#xD;
var&#xD;
  I: Integer;&#xD;
begin&#xD;
  if not (FMode in [zmReadWrite, zmRead]) then&#xD;
    raise EZipException.CreateRes(@SZipNoRead);&#xD;
  for I := 0 to FFiles.Count - 1 do&#xD;
  begin                                           ///&#xD;
    Extract(I, Path);&#xD;
    DoUnZipProgress(FileCount, I+1, FileName[I]); ///&#xD;
  end;                                            ///&#xD;
end;&#xD;
&#xD;
procedure TZipFile.Read(FileName: string; out Bytes: TBytes);&#xD;
begin&#xD;
  Read(IndexOf(FileName), Bytes);&#xD;
end;&#xD;
&#xD;
procedure TZipFile.Read(Index: Integer; out Bytes: TBytes);&#xD;
var&#xD;
  LStream: TStream;&#xD;
  LHeader: TZipHeader;&#xD;
  ReadStart, ReadBytes: Int64;&#xD;
begin&#xD;
  Read(Index, LStream, LHeader);&#xD;
  try&#xD;
    if (LHeader.Flag and (1 SHL 3)) = 0 then&#xD;
    begin&#xD;
      SetLength(Bytes, FFiles[Index].UncompressedSize);&#xD;
      if FFiles[Index].UncompressedSize &amp;gt; 0 then&#xD;
        VerifyRead(LStream, Bytes[0], LHeader.UncompressedSize);&#xD;
    end&#xD;
    else&#xD;
    begin&#xD;
      SetLength(Bytes, 4096);&#xD;
      ReadStart := 0;&#xD;
      ReadBytes := 0;&#xD;
      while True do&#xD;
      begin&#xD;
        ReadBytes := LStream.Read(Bytes[ReadStart], Length(Bytes)-ReadStart);&#xD;
        if ReadBytes &amp;lt; (Length(Bytes) - ReadStart) then&#xD;
          break;&#xD;
        ReadStart := ReadStart + ReadBytes;&#xD;
        SetLength(Bytes, Length(Bytes)*2);&#xD;
      end;&#xD;
      SetLength(Bytes, ReadStart + ReadBytes);&#xD;
    end;&#xD;
  finally&#xD;
    LStream.Free;&#xD;
  end;&#xD;
end;&#xD;
&#xD;
procedure TZipFile.Read(FileName: string; out Stream: TStream; out LocalHeader: TZipHeader);&#xD;
begin&#xD;
  Read(IndexOf(FileName), Stream, LocalHeader);&#xD;
end;&#xD;
&#xD;
procedure TZipFile.Read(Index: Integer; out Stream: TStream; out LocalHeader: TZipHeader);&#xD;
var&#xD;
  Signature: UInt32;&#xD;
begin&#xD;
  if not (FMode in [zmReadWrite, zmRead]) then&#xD;
    raise EZipException.CreateRes(@SZipNoRead);&#xD;
&#xD;
  if (Index &amp;lt; 0) or (Index &amp;gt; FFiles.Count) then&#xD;
    raise EZipException.CreateRes(@SFileNotFound);&#xD;
&#xD;
  LocalHeader.MadeByVersion := 0;&#xD;
  LocalHeader.FileComment        := '';&#xD;
  LocalHeader.FileCommentLength  := 0;&#xD;
  LocalHeader.DiskNumberStart    := 0;&#xD;
  LocalHeader.InternalAttributes := 0;&#xD;
  LocalHeader.ExternalAttributes := 0;&#xD;
  LocalHeader.LocalHeaderOffset  := 0;&#xD;
&#xD;
  FStream.Position := FFiles[Index].LocalHeaderOffset + FStartFileData;&#xD;
  FStream.Read(Signature, Sizeof(Signature));&#xD;
  if Signature &amp;lt;&amp;gt; SIGNATURE_LOCALHEADER then&#xD;
    raise EZipException.CreateRes(@SZipInvalidLocalHeader);&#xD;
  FStream.Read(LocalHeader.RequiredVersion, LOCALHEADERSIZE);&#xD;
  SetLength(LocalHeader.FileName, LocalHeader.FileNameLength);&#xD;
  SetLength(LocalHeader.ExtraField, LocalHeader.ExtraFieldLength);&#xD;
  if (LocalHeader.Flag and (1 SHL 11)) &amp;lt;&amp;gt; 0 then&#xD;
    SetCodepage(LocalHeader.FileName, 65001, False)&#xD;
  else&#xD;
    SetCodepage(LocalHeader.FileName, 437, False);&#xD;
  FStream.Read(LocalHeader.FileName[1], LocalHeader.FileNameLength);&#xD;
  if LocalHeader.ExtraFieldLength &amp;gt; 0 then&#xD;
    FStream.Read(LocalHeader.ExtraField[0], LocalHeader.ExtraFieldLength);&#xD;
  Stream := FCompressionHandler[TZipCompression(FFiles[Index].CompressionMethod)].Value(FStream, Self, LocalHeader);&#xD;
end;&#xD;
&#xD;
procedure TZipFile.Add(Data: TStream; LocalHeader: TZipHeader; CentralHeader: PZipHeader);&#xD;
var&#xD;
  DataStart: Int64;&#xD;
  LCompressStream: TStream;&#xD;
  Signature: UInt32;&#xD;
  LStartPos: Int64;&#xD;
  LBuffer: array[0..$4000] of Byte;&#xD;
begin&#xD;
  FStream.Position := FEndFileData;&#xD;
  LocalHeader.LocalHeaderOffset := FEndFileData;&#xD;
  if LocalHeader.MadeByVersion &amp;lt; 20 then&#xD;
    LocalHeader.MadeByVersion := 20;&#xD;
  if LocalHeader.RequiredVersion &amp;lt; 20 then&#xD;
    LocalHeader.RequiredVersion := 20;&#xD;
&#xD;
  LocalHeader.FileNameLength   := Length(LocalHeader.FileName);&#xD;
  LocalHeader.ExtraFieldLength := Length(LocalHeader.ExtraField);&#xD;
&#xD;
  if CentralHeader = nil then&#xD;
    CentralHeader := @LocalHeader&#xD;
  else&#xD;
  begin&#xD;
    CentralHeader^.FileNameLength   := Length(CentralHeader^.FileName);&#xD;
    CentralHeader^.ExtraFieldLength := Length(CentralHeader^.ExtraField);&#xD;
  end;&#xD;
  CentralHeader^.FileCommentLength  := Length(CentralHeader^.FileComment);&#xD;
&#xD;
  Signature := SIGNATURE_LOCALHEADER;&#xD;
  VerifyWrite(FStream, Signature, SizeOf(Signature));&#xD;
  VerifyWrite(FStream, LocalHeader.RequiredVersion, LOCALHEADERSIZE);&#xD;
  VerifyWrite(FStream, LocalHeader.FileName[1], LocalHeader.FileNameLength);&#xD;
  if LocalHeader.ExtraFieldLength &amp;gt; 0 then&#xD;
    VerifyWrite(FStream, LocalHeader.ExtraField[0], LocalHeader.ExtraFieldLength);&#xD;
  LStartPos := FStream.Position;&#xD;
  DataStart := Data.Position;&#xD;
  LocalHeader.UncompressedSize := Data.Size - DataStart;&#xD;
  LCompressStream := FCompressionHandler[TZipCompression(LocalHeader.CompressionMethod)].Key(FStream, self, LocalHeader);&#xD;
  try&#xD;
    LCompressStream.CopyFrom(Data, LocalHeader.UncompressedSize);&#xD;
  finally&#xD;
    LCompressStream.Free;&#xD;
  end;&#xD;
&#xD;
  LocalHeader.CompressedSize := FStream.Position - LStartPos;&#xD;
  Data.Position := DataStart;&#xD;
  while Data.Position &amp;lt; LocalHeader.UncompressedSize do&#xD;
    LocalHeader.CRC32 := crc32(LocalHeader.CRC32, @LBuffer[0],&#xD;
      Data.Read(LBuffer, SizeOf(LBuffer)));&#xD;
  CentralHeader.UnCompressedSize := LocalHeader.UnCompressedSize;&#xD;
  CentralHeader.CompressedSize := LocalHeader.CompressedSize;&#xD;
  CentralHeader.CRC32 := LocalHeader.CRC32;&#xD;
  FEndFileData := FStream.Position;&#xD;
  FStream.Position := LocalHeader.LocalHeaderOffset + SizeOf(UInt32);&#xD;
  FStream.Write(LocalHeader.RequiredVersion, LOCALHEADERSIZE);&#xD;
  FFiles.Add(CentralHeader^);&#xD;
end;&#xD;
&#xD;
procedure TZipFile.Add(FileName: string; ArchiveFileName: string;&#xD;
  Compression: TZipCompression);&#xD;
var&#xD;
  LInStream: TStream;&#xD;
  LHeader: TZipHeader;&#xD;
begin&#xD;
  if not (FMode in [zmReadWrite, zmWrite]) then&#xD;
    raise EZipException.CreateRes(@SZipNoWrite);&#xD;
&#xD;
  if not FCompressionHandler.ContainsKey(Compression) then&#xD;
    raise EZipException.CreateResFmt(@SZipNotSupported, [&#xD;
      TZipCompressionToString(Compression) ]);&#xD;
&#xD;
  FillChar(LHeader, sizeof(LHeader), 0);&#xD;
  LHeader.Flag := 0;&#xD;
  LInStream := TFileStream.Create(FileName, fmOpenRead);&#xD;
  try&#xD;
    LHeader.Flag := 0;&#xD;
    LHeader.CompressionMethod := UInt16(Compression);&#xD;
    LHeader.ModifiedDateTime := DateTimeToFileDate( tfile.GetLastWriteTime(FileName) );&#xD;
    LHeader.UncompressedSize := LInStream.Size;&#xD;
    LHeader.InternalAttributes := 0;&#xD;
    LHeader.ExternalAttributes := 0;&#xD;
    if ArchiveFileName = '' then&#xD;
      ArchiveFileName := ExtractFileName(FileName);&#xD;
    if FUTF8Support then&#xD;
    begin&#xD;
      LHeader.Flag := LHeader.Flag or (1 SHL 11);&#xD;
      LHeader.FileName := UTF8Encode(ArchiveFileName);&#xD;
    end&#xD;
    else&#xD;
      LHeader.FileName := TOem437String(ArchiveFileName);&#xD;
    LHeader.FileNameLength := Length(LHeader.FileName);&#xD;
&#xD;
    LHeader.ExtraFieldLength := 0;&#xD;
    Add(LInStream, LHeader);&#xD;
  finally&#xD;
    LInStream.Free;&#xD;
  end;&#xD;
end;&#xD;
&#xD;
procedure TZipFile.Add(Data: TBytes; ArchiveFileName: string;&#xD;
  Compression: TZipCompression);&#xD;
var&#xD;
  LInStream: TStream;&#xD;
begin&#xD;
  if not (FMode in [zmReadWrite, zmWrite]) then&#xD;
    raise EZipException.CreateRes(@SZipNoWrite);&#xD;
&#xD;
  if not FCompressionHandler.ContainsKey(Compression) then&#xD;
    raise EZipException.CreateResFmt(@SZipNotSupported, [&#xD;
      TZipCompressionToString(Compression) ]);&#xD;
&#xD;
  LInStream := TBytesStream.Create(Data);&#xD;
  try&#xD;
    Add(LInStream, ArchiveFileName, Compression);&#xD;
  finally&#xD;
    LInStream.Free;&#xD;
  end;&#xD;
end;&#xD;
&#xD;
procedure TZipFile.Add(Data: TStream; ArchiveFileName: string;&#xD;
  Compression: TZipCompression);&#xD;
var&#xD;
  LHeader: TZipHeader;&#xD;
begin&#xD;
  if not (FMode in [zmReadWrite, zmWrite]) then&#xD;
    raise EZipException.CreateRes(@SZipNoWrite);&#xD;
&#xD;
  if not FCompressionHandler.ContainsKey(Compression) then&#xD;
    raise EZipException.CreateResFmt(@SZipNotSupported, [&#xD;
      TZipCompressionToString(Compression) ]);&#xD;
&#xD;
  FillChar(LHeader, sizeof(LHeader), 0);&#xD;
  LHeader.Flag := 0;&#xD;
  LHeader.CompressionMethod := UInt16(Compression);&#xD;
  LHeader.ModifiedDateTime := DateTimeToFileDate( Now );&#xD;
  LHeader.InternalAttributes := 0;&#xD;
  LHeader.ExternalAttributes := 0;&#xD;
  if FUTF8Support then&#xD;
  begin&#xD;
    LHeader.Flag := LHeader.Flag or (1 SHL 11);&#xD;
    LHeader.FileName := UTF8Encode(ArchiveFileName);&#xD;
  end&#xD;
  else&#xD;
    LHeader.FileName := TOem437String(ArchiveFileName);&#xD;
  LHeader.FileNameLength := Length(LHeader.FileName);&#xD;
&#xD;
  LHeader.ExtraFieldLength := 0;&#xD;
  Add(Data, LHeader);&#xD;
end;&#xD;
&#xD;
function TZipFile.IndexOf(FileName: string): Integer;&#xD;
var&#xD;
  I: Integer;&#xD;
begin&#xD;
  Result := -1;&#xD;
  for I := 0 to FFiles.Count - 1 do&#xD;
    if string(FFiles[I].FileName) = FileName then&#xD;
      Exit(I);&#xD;
end;&#xD;
&#xD;
end.&#xD;
&lt;/pre&gt;&lt;hr/&gt;&#xD;
&lt;br/&gt;&#xD;
&#xD;
测试:&lt;hr/&gt;&lt;br/&gt;&lt;pre &gt;unit Unit1;&#xD;
&#xD;
interface&#xD;
&#xD;
uses&#xD;
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,&#xD;
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;&#xD;
&#xD;
type&#xD;
  TForm1 = class(TForm)&#xD;
    Button1: TButton;&#xD;
    procedure Button1Click(Sender: TObject);&#xD;
    procedure OnProgress(Sender: TObject; ACount,AIndex: Integer; AFileName: string);&#xD;
  end;&#xD;
&#xD;
var&#xD;
  Form1: TForm1;&#xD;
&#xD;
implementation&#xD;
&#xD;
{$R *.dfm}&#xD;
&#xD;
uses Zip2;&#xD;
&#xD;
procedure TForm1.Button1Click(Sender: TObject);&#xD;
begin&#xD;
  with TZipFile.Create do&#xD;
  begin&#xD;
    OnUnZipProgress := OnProgress;&#xD;
    Open('C:\Temp\Test.zip', zmRead);&#xD;
    ExtractAll('C:\Temp\Test\');&#xD;
    Free;&#xD;
  end;&#xD;
end;&#xD;
&#xD;
procedure TForm1.OnProgress(Sender: TObject; ACount, AIndex: Integer; AFileName: string);&#xD;
begin&#xD;
  Caption := Format('%d/%d: %s', [AIndex, ACount, AFileName]);&#xD;
  Application.ProcessMessages;&#xD;
end;&#xD;
&#xD;
end.&#xD;
&lt;/pre&gt;&lt;hr/&gt;&#xD;
&lt;img src="http://www.cnblogs.com/del/aggbug/2337938.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/del/archive/2012/02/04/2337938.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/del/archive/2012/01/05/2313410.html</id><title type="text">把一个&amp;quot;结构体&amp;quot;当做属性后碰到的问题</title><summary type="text">当我把一个&amp;quot;结构体&amp;quot;在类中当做属性后, 在实用中可以直接读取结构体成员, 但不能直接写入...下面是由此引发的小练习:unit Unit1;interfaceuses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;type TForm1 = class(TForm) Button1: TButton; Button2: TBut</summary><published>2012-01-05T08:56:00Z</published><updated>2012-01-05T08:56:00Z</updated><author><name>万一</name><uri>http://www.cnblogs.com/del/</uri></author><link rel="alternate" href="http://www.cnblogs.com/del/archive/2012/01/05/2313410.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/del/archive/2012/01/05/2313410.html"/><content type="html">&lt;br/&gt;&#xD;
当我把一个"结构体"在类中当做属性后, 在实用中可以直接读取结构体成员, 但不能直接写入...&lt;br/&gt;&lt;br/&gt;&#xD;
&#xD;
下面是由此引发的小练习:&lt;hr/&gt;&#xD;
&lt;br/&gt;&lt;pre &gt;unit Unit1;&#xD;
&#xD;
interface&#xD;
&#xD;
uses&#xD;
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,&#xD;
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;&#xD;
&#xD;
type&#xD;
  TForm1 = class(TForm)&#xD;
    Button1: TButton;&#xD;
    Button2: TButton;&#xD;
    Button3: TButton;&#xD;
    Button4: TButton;&#xD;
    Button5: TButton;&#xD;
    procedure Button1Click(Sender: TObject);&#xD;
    procedure Button2Click(Sender: TObject);&#xD;
    procedure Button4Click(Sender: TObject);&#xD;
    procedure Button3Click(Sender: TObject);&#xD;
    procedure Button5Click(Sender: TObject);&#xD;
  end;&#xD;
&#xD;
  TMyClass = class&#xD;
  strict private&#xD;
    FPos: TPoint;&#xD;
    procedure SetPos(const Value: TPoint);&#xD;
  public&#xD;
    property Pos: TPoint read FPos write SetPos; //属性 Pos 对应一个点结构&#xD;
  end;&#xD;
&#xD;
var&#xD;
  Form1: TForm1;&#xD;
&#xD;
implementation&#xD;
&#xD;
{$R *.dfm}&#xD;
&#xD;
{ TMyClass }&#xD;
&#xD;
procedure TMyClass.SetPos(const Value: TPoint);&#xD;
begin&#xD;
  FPos := Value;&#xD;
end;&#xD;
&#xD;
&#xD;
{测试}&#xD;
&#xD;
procedure TForm1.Button1Click(Sender: TObject);&#xD;
var&#xD;
  obj: TMyClass;&#xD;
begin&#xD;
  obj := TMyClass.Create;&#xD;
  ShowMessageFmt('%d, %d', [obj.Pos.X, obj.Pos.Y]); //可以直接访问结构中的元素&#xD;
//  obj.Pos.X := 11;  //但不能直接给结构中的元素赋值&#xD;
//  obj.Pos.Y := 22;&#xD;
  obj.Free;&#xD;
end;&#xD;
&#xD;
//变通一&#xD;
procedure TForm1.Button2Click(Sender: TObject);&#xD;
var&#xD;
  obj: TMyClass;&#xD;
begin&#xD;
  obj := TMyClass.Create;&#xD;
  obj.Pos := Point(22,33); //&#xD;
  ShowMessageFmt('%d, %d', [obj.Pos.X, obj.Pos.Y]);&#xD;
  obj.Free;&#xD;
end;&#xD;
&#xD;
//变通二&#xD;
procedure TForm1.Button3Click(Sender: TObject);&#xD;
var&#xD;
  obj: TMyClass;&#xD;
  pt: TPoint;&#xD;
begin&#xD;
  obj := TMyClass.Create;&#xD;
  pt.X := 33;&#xD;
  pt.Y := 44;&#xD;
  obj.Pos := pt;&#xD;
  ShowMessageFmt('%d, %d', [obj.Pos.X, obj.Pos.Y]);&#xD;
  obj.Free;&#xD;
end;&#xD;
&#xD;
//变通三(假如属性的 get 不是方法)&#xD;
procedure TForm1.Button4Click(Sender: TObject);&#xD;
var&#xD;
  obj: TMyClass;&#xD;
  p: PPoint;&#xD;
begin&#xD;
  obj := TMyClass.Create;&#xD;
  p := Addr(obj.Pos);&#xD;
  p.X := 44;&#xD;
  p.Y := 55;&#xD;
  ShowMessageFmt('%d, %d', [obj.Pos.X, obj.Pos.Y]);&#xD;
  obj.Free;&#xD;
end;&#xD;
&#xD;
//变通四(假如属性的 get 不是方法)&#xD;
procedure TForm1.Button5Click(Sender: TObject);&#xD;
var&#xD;
  obj: TMyClass;&#xD;
begin&#xD;
  obj := TMyClass.Create;&#xD;
  PPoint(Addr(obj.Pos)).X := 55;&#xD;
  PPoint(Addr(obj.Pos)).Y := 66;&#xD;
  ShowMessageFmt('%d, %d', [obj.Pos.X, obj.Pos.Y]);&#xD;
  obj.Free;&#xD;
end;&#xD;
&#xD;
end.&#xD;
&lt;/pre&gt;&lt;hr/&gt;&#xD;
&#xD;
&lt;br/&gt;&#xD;
练习二:&lt;hr/&gt;&#xD;
&lt;br/&gt;&lt;pre &gt;unit Unit1;&#xD;
&#xD;
interface&#xD;
&#xD;
uses&#xD;
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,&#xD;
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs;&#xD;
&#xD;
type&#xD;
  TForm1 = class(TForm)&#xD;
    procedure FormCreate(Sender: TObject);&#xD;
  end;&#xD;
&#xD;
  TMyClass = class&#xD;
  private&#xD;
    FPos: TPoint;&#xD;
    function GetPos: TPoint;&#xD;
    procedure SetPos(const Value: TPoint);&#xD;
    function GetXY(const Index: Integer): Integer;&#xD;
    procedure SetXY(const Index, Value: Integer);&#xD;
  public&#xD;
    property Pos: TPoint read GetPos write SetPos;&#xD;
    property X: Integer index 0 read GetXY write SetXY;&#xD;
    property Y: Integer index 1 read GetXY write SetXY;&#xD;
  end;&#xD;
&#xD;
var&#xD;
  Form1: TForm1;&#xD;
&#xD;
implementation&#xD;
&#xD;
{$R *.dfm}&#xD;
&#xD;
{ TMyClass }&#xD;
&#xD;
function TMyClass.GetPos: TPoint;&#xD;
begin&#xD;
  Result := FPos;&#xD;
end;&#xD;
&#xD;
procedure TMyClass.SetPos(const Value: TPoint);&#xD;
begin&#xD;
  FPos := Value;&#xD;
end;&#xD;
&#xD;
function TMyClass.GetXY(const Index: Integer): Integer;&#xD;
begin&#xD;
  Result := 0;&#xD;
  case Index of&#xD;
    0: Result := FPos.X;&#xD;
    1: Result := FPos.Y;&#xD;
  end;&#xD;
end;&#xD;
&#xD;
procedure TMyClass.SetXY(const Index, Value: Integer);&#xD;
begin&#xD;
  case Index of&#xD;
    0: FPos.X := Value;&#xD;
    1: FPos.Y := Value;&#xD;
  end;&#xD;
end;&#xD;
&#xD;
{测试}&#xD;
procedure TForm1.FormCreate(Sender: TObject);&#xD;
var&#xD;
  obj: TMyClass;&#xD;
begin&#xD;
  obj := TMyClass.Create;&#xD;
  obj.X := 11;&#xD;
  obj.Y := 22;&#xD;
  ShowMessageFmt('%d, %d', [obj.Pos.X, obj.Pos.Y]);&#xD;
  obj.Free;&#xD;
end;&#xD;
&#xD;
end.&#xD;
&lt;/pre&gt;&lt;hr/&gt;&lt;img src="http://www.cnblogs.com/del/aggbug/2313410.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/del/archive/2012/01/05/2313410.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/del/archive/2012/01/03/2311372.html</id><title type="text">覆盖、再覆盖</title><summary type="text">在实践中真的会发现更多问题.unit Unit1;interfaceuses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs;type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); end; IA = Interface function GetName: string; p...</summary><published>2012-01-03T14:09:00Z</published><updated>2012-01-03T14:09:00Z</updated><author><name>万一</name><uri>http://www.cnblogs.com/del/</uri></author><link rel="alternate" href="http://www.cnblogs.com/del/archive/2012/01/03/2311372.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/del/archive/2012/01/03/2311372.html"/><content type="html">&lt;br/&gt;&#xD;
在实践中真的会发现更多问题.&lt;hr/&gt;&#xD;
&lt;br/&gt;&lt;pre &gt;unit Unit1;&#xD;
&#xD;
interface&#xD;
&#xD;
uses&#xD;
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,&#xD;
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs;&#xD;
&#xD;
type&#xD;
  TForm1 = class(TForm)&#xD;
    procedure FormCreate(Sender: TObject);&#xD;
  end;&#xD;
&#xD;
  IA = Interface&#xD;
    function GetName: string;&#xD;
    property Name: string read GetName;&#xD;
  end;&#xD;
&#xD;
  TC1 = class(TInterfacedObject, IA)&#xD;
    function GetName: string; virtual;&#xD;
  end;&#xD;
&#xD;
  TC2 = class(TC1)&#xD;
    function GetName: string; override; //覆盖&#xD;
  end;&#xD;
&#xD;
  TC3 = class(TC2)&#xD;
    function GetName: string; override; //再覆盖&#xD;
  end;&#xD;
&#xD;
  TC4 = class(TC3)&#xD;
    function GetName: string; override; //再覆盖&#xD;
  end;&#xD;
&#xD;
var&#xD;
  Form1: TForm1;&#xD;
&#xD;
implementation&#xD;
&#xD;
{$R *.dfm}&#xD;
&#xD;
{ TC1 }&#xD;
&#xD;
function TC1.GetName: string;&#xD;
begin&#xD;
  Result := 'C1';&#xD;
end;&#xD;
&#xD;
{ TC2 }&#xD;
&#xD;
function TC2.GetName: string;&#xD;
begin&#xD;
  Result := 'C2';&#xD;
end;&#xD;
&#xD;
{ TC3 }&#xD;
&#xD;
function TC3.GetName: string;&#xD;
begin&#xD;
  Result := 'C3';&#xD;
end;&#xD;
&#xD;
{ TC4 }&#xD;
&#xD;
function TC4.GetName: string;&#xD;
begin&#xD;
  Result := inherited + '0';&#xD;
end;&#xD;
&#xD;
&#xD;
{测试}&#xD;
procedure TForm1.FormCreate(Sender: TObject);&#xD;
var&#xD;
  v1,v2,v3,v4: IA;&#xD;
begin&#xD;
  v1 := TC1.Create;&#xD;
  v2 := TC2.Create;&#xD;
  v3 := TC3.Create;&#xD;
  v4 := TC4.Create;&#xD;
  ShowMessageFmt('%s, %s, %s, %s', [v1.Name, v2.Name, v3.Name, v4.Name]); //C1, C2, C3, C30&#xD;
end;&#xD;
&#xD;
end.&#xD;
&lt;/pre&gt;&lt;hr/&gt;&lt;img src="http://www.cnblogs.com/del/aggbug/2311372.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/del/archive/2012/01/03/2311372.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/del/archive/2012/01/03/2311077.html</id><title type="text">以接口为主导的设计中, 我在使用的框架模式</title><summary type="text">在今后的 Delphi 中, 以接口、结构为主的设计应该会越来越多, 因为这样太方便了.System.RegularExpressions 就是以结构为主体设计的非常好的示范; 但更多东西使用接口会更合适.有见过他人早就使用接口写程序, 从手头的这个程序开始我才开始使用.现在基本总结出四种框架模式: 1、直接实现; 2、间接实现(或叫继承实现); 3、覆盖实现; 4、委托实现.一、直接实现:下例中虽有 TMy1、TMy2, 但在具体应用中使用的应是 IMy1、IMy2, 这就是我所谓的以接口为主导.TMy1、TMy2 直接实现了所属接口的所有方法, 这是我所谓的直接实现.这样可能会有代码重复,</summary><published>2012-01-03T10:01:00Z</published><updated>2012-01-03T10:01:00Z</updated><author><name>万一</name><uri>http://www.cnblogs.com/del/</uri></author><link rel="alternate" href="http://www.cnblogs.com/del/archive/2012/01/03/2311077.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/del/archive/2012/01/03/2311077.html"/><content type="html">&lt;br/&gt;&#xD;
在今后的 Delphi 中, 以接口、结构为主的设计应该会越来越多, 因为这样太方便了.&lt;br/&gt;&lt;br/&gt;&#xD;
&#xD;
System.RegularExpressions 就是以结构为主体设计的非常好的示范; 但更多东西使用接口会更合适.&lt;br/&gt;&lt;br/&gt;&#xD;
&#xD;
有见过他人早就使用接口写程序, 从手头的这个程序开始我才开始使用.&lt;br/&gt;&lt;br/&gt;&#xD;
&#xD;
现在基本总结出四种框架模式: 1、直接实现; 2、间接实现(或叫继承实现); 3、覆盖实现; 4、委托实现.&lt;hr/&gt;&lt;br/&gt;&#xD;
&#xD;
一、直接实现:&lt;br/&gt;&lt;br/&gt;&#xD;
下例中虽有 TMy1、TMy2, 但在具体应用中使用的应是 IMy1、IMy2, 这就是我所谓的以接口为主导.&lt;br/&gt;&#xD;
TMy1、TMy2 直接实现了所属接口的所有方法, 这是我所谓的直接实现.&lt;br/&gt;&#xD;
这样可能会有代码重复, 但如果程序很小, 还是挺实用的.&lt;hr/&gt;&#xD;
&lt;br/&gt;&lt;pre &gt;unit Unit1;&#xD;
&#xD;
interface&#xD;
&#xD;
uses&#xD;
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,&#xD;
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs;&#xD;
&#xD;
type&#xD;
  TForm1 = class(TForm)&#xD;
    procedure FormCreate(Sender: TObject);&#xD;
  end;&#xD;
&#xD;
  IA = Interface&#xD;
    procedure Method_A;&#xD;
  end;&#xD;
&#xD;
  IB = Interface(IA)&#xD;
    procedure Method_B;&#xD;
  end;&#xD;
&#xD;
  IMy1 = Interface(IB)&#xD;
    procedure Method_My1;&#xD;
  end;&#xD;
&#xD;
  IMy2 = Interface(IB)&#xD;
    procedure Method_My2;&#xD;
  end;&#xD;
&#xD;
  TMy1 = class(TInterfacedObject, IMy1)&#xD;
    procedure Method_A;&#xD;
    procedure Method_B;&#xD;
    procedure Method_My1;&#xD;
  end;&#xD;
&#xD;
  TMy2 = class(TInterfacedObject, IMy2)&#xD;
    procedure Method_A;&#xD;
    procedure Method_B;&#xD;
    procedure Method_My2;&#xD;
  end;&#xD;
&#xD;
var&#xD;
  Form1: TForm1;&#xD;
&#xD;
implementation&#xD;
&#xD;
{$R *.dfm}&#xD;
&#xD;
{ TMy1 }&#xD;
&#xD;
procedure TMy1.Method_A;&#xD;
begin&#xD;
  ShowMessage('A');&#xD;
end;&#xD;
&#xD;
procedure TMy1.Method_B;&#xD;
begin&#xD;
  ShowMessage('B');&#xD;
end;&#xD;
&#xD;
procedure TMy1.Method_My1;&#xD;
begin&#xD;
  ShowMessage('My1');&#xD;
end;&#xD;
&#xD;
{ TMy2 }&#xD;
&#xD;
procedure TMy2.Method_A;&#xD;
begin&#xD;
  ShowMessage('A');&#xD;
end;&#xD;
&#xD;
procedure TMy2.Method_B;&#xD;
begin&#xD;
  ShowMessage('B');&#xD;
end;&#xD;
&#xD;
procedure TMy2.Method_My2;&#xD;
begin&#xD;
  ShowMessage('My2');&#xD;
end;&#xD;
&#xD;
{测试}&#xD;
procedure TForm1.FormCreate(Sender: TObject);&#xD;
var&#xD;
  v1: IMy1;&#xD;
  v2: IMy2;&#xD;
begin&#xD;
  v1 := TMy1.Create;&#xD;
  v1.Method_A;&#xD;
  v1.Method_B;&#xD;
  v1.Method_My1;&#xD;
&#xD;
  v2 := TMy2.Create;&#xD;
  v2.Method_A;&#xD;
  v2.Method_B;&#xD;
  v2.Method_My2;&#xD;
end;&#xD;
&#xD;
end.&#xD;
&lt;/pre&gt;&lt;hr/&gt;&#xD;
&#xD;
&lt;br/&gt;&#xD;
二、间接实现:&lt;br/&gt;&lt;br/&gt;&#xD;
下面例子通过一个间接的 TB 类, 避免了 TMy1、TMy2 中可能会重复的代码.&lt;hr/&gt;&#xD;
&lt;br/&gt;&lt;pre &gt;unit Unit1;&#xD;
&#xD;
interface&#xD;
&#xD;
uses&#xD;
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,&#xD;
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs;&#xD;
&#xD;
type&#xD;
  TForm1 = class(TForm)&#xD;
    procedure FormCreate(Sender: TObject);&#xD;
  end;&#xD;
&#xD;
  IA = Interface&#xD;
    procedure Method_A;&#xD;
  end;&#xD;
&#xD;
  IB = Interface(IA)&#xD;
    procedure Method_B;&#xD;
  end;&#xD;
&#xD;
  TB = class(TInterfacedObject, IB)&#xD;
    procedure Method_A;&#xD;
    procedure Method_B;&#xD;
  end;&#xD;
&#xD;
  IMy1 = Interface(IB)&#xD;
    procedure Method_My1;&#xD;
  end;&#xD;
&#xD;
  IMy2 = Interface(IB)&#xD;
    procedure Method_My2;&#xD;
  end;&#xD;
&#xD;
  TMy1 = class(TB, IMy1)&#xD;
    procedure Method_My1;&#xD;
  end;&#xD;
&#xD;
  TMy2 = class(TB, IMy2)&#xD;
    procedure Method_My2;&#xD;
  end;&#xD;
&#xD;
var&#xD;
  Form1: TForm1;&#xD;
&#xD;
implementation&#xD;
&#xD;
{$R *.dfm}&#xD;
&#xD;
{ TB }&#xD;
&#xD;
procedure TB.Method_A;&#xD;
begin&#xD;
  ShowMessage('A');&#xD;
end;&#xD;
&#xD;
procedure TB.Method_B;&#xD;
begin&#xD;
  ShowMessage('B');&#xD;
end;&#xD;
&#xD;
{ TMy1 }&#xD;
&#xD;
procedure TMy1.Method_My1;&#xD;
begin&#xD;
  ShowMessage('My1');&#xD;
end;&#xD;
&#xD;
{ TMy2 }&#xD;
&#xD;
procedure TMy2.Method_My2;&#xD;
begin&#xD;
  ShowMessage('My2');&#xD;
end;&#xD;
&#xD;
{测试}&#xD;
procedure TForm1.FormCreate(Sender: TObject);&#xD;
var&#xD;
  v1: IMy1;&#xD;
  v2: IMy2;&#xD;
begin&#xD;
  v1 := TMy1.Create;&#xD;
  v1.Method_A;&#xD;
  v1.Method_B;&#xD;
  v1.Method_My1;&#xD;
&#xD;
  v2 := TMy2.Create;&#xD;
  v2.Method_A;&#xD;
  v2.Method_B;&#xD;
  v2.Method_My2;&#xD;
end;&#xD;
&#xD;
end.&#xD;
&lt;/pre&gt;&lt;hr/&gt;&#xD;
&#xD;
&lt;br/&gt;&#xD;
三、覆盖实现:&lt;br/&gt;&lt;br/&gt;&#xD;
从 TB 继承的过程中当然也可以通过覆盖虚函数而实现多态, 下面的 TMy2 就这么做了.&lt;hr/&gt;&#xD;
&lt;br/&gt;&lt;pre &gt;unit Unit1;&#xD;
&#xD;
interface&#xD;
&#xD;
uses&#xD;
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,&#xD;
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs;&#xD;
&#xD;
type&#xD;
  TForm1 = class(TForm)&#xD;
    procedure FormCreate(Sender: TObject);&#xD;
  end;&#xD;
&#xD;
  IA = Interface&#xD;
    procedure Method_A;&#xD;
  end;&#xD;
&#xD;
  IB = Interface(IA)&#xD;
    procedure Method_B;&#xD;
  end;&#xD;
&#xD;
  TB = class(TInterfacedObject, IB)&#xD;
    procedure Method_A; virtual;&#xD;
    procedure Method_B; virtual;&#xD;
  end;&#xD;
&#xD;
  IMy1 = Interface(IB)&#xD;
    procedure Method_My1;&#xD;
  end;&#xD;
&#xD;
  IMy2 = Interface(IB)&#xD;
    procedure Method_My2;&#xD;
  end;&#xD;
&#xD;
  TMy1 = class(TB, IMy1)&#xD;
    procedure Method_My1;&#xD;
  end;&#xD;
&#xD;
  TMy2 = class(TB, IMy2)&#xD;
    procedure Method_A; override;&#xD;
    procedure Method_B; override;&#xD;
    procedure Method_My2;&#xD;
  end;&#xD;
&#xD;
var&#xD;
  Form1: TForm1;&#xD;
&#xD;
implementation&#xD;
&#xD;
{$R *.dfm}&#xD;
&#xD;
{ TB }&#xD;
&#xD;
procedure TB.Method_A;&#xD;
begin&#xD;
  ShowMessage('A');&#xD;
end;&#xD;
&#xD;
procedure TB.Method_B;&#xD;
begin&#xD;
  ShowMessage('B');&#xD;
end;&#xD;
&#xD;
{ TMy1 }&#xD;
&#xD;
procedure TMy1.Method_My1;&#xD;
begin&#xD;
  ShowMessage('My1');&#xD;
end;&#xD;
&#xD;
{ TMy2 }&#xD;
&#xD;
procedure TMy2.Method_A;&#xD;
begin&#xD;
  ShowMessage('A_My2');&#xD;
end;&#xD;
&#xD;
procedure TMy2.Method_B;&#xD;
begin&#xD;
  ShowMessage('B_My2');&#xD;
end;&#xD;
&#xD;
procedure TMy2.Method_My2;&#xD;
begin&#xD;
  ShowMessage('My2');&#xD;
end;&#xD;
&#xD;
{测试}&#xD;
procedure TForm1.FormCreate(Sender: TObject);&#xD;
var&#xD;
  v1: IMy1;&#xD;
  v2: IMy2;&#xD;
begin&#xD;
  v1 := TMy1.Create;&#xD;
  v1.Method_A;&#xD;
  v1.Method_B;&#xD;
  v1.Method_My1;&#xD;
&#xD;
  v2 := TMy2.Create;&#xD;
  v2.Method_A;&#xD;
  v2.Method_B;&#xD;
  v2.Method_My2;&#xD;
end;&#xD;
&#xD;
end.&#xD;
&lt;/pre&gt;&lt;hr/&gt;&#xD;
&lt;br/&gt;&#xD;
四、委托实现:&lt;br/&gt;&lt;br/&gt;&#xD;
接口中的方法是肯定要实现的, 但也可以通过 implements 关键字借用(或叫委托)其它的实现;&lt;br/&gt;&#xD;
但, 官方文档说这只适用于 Win32. 就是说这种方法在 Win64 和其它系统都不行, 还学它干嘛?&lt;hr/&gt;&lt;br/&gt;&lt;img src="http://www.cnblogs.com/del/aggbug/2311077.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/del/archive/2012/01/03/2311077.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/del/archive/2011/12/31/2308656.html</id><title type="text">混合排序小练习</title><summary type="text">2011 年的最后一天了...混合排序 -&amp;gt; 搅乱、重新洗牌; 以 Integer 动态数组为例.//两个辅助函数 Swap、ToStr, 分别用于交换数组元素和呈现为字符串procedure Swap(var Arr: TArray&amp;lt;Integer&amp;gt;; a,b: Cardinal);var tmp: Integer;begin if (a &amp;gt;= Length(Arr)) or (b &amp;gt;= Length(Arr)) or (a = b) then Exit; tmp := Arr[a]; Arr[a] := Arr[b]; Arr[b] := tmp;end;fu</summary><published>2011-12-31T05:30:00Z</published><updated>2011-12-31T05:30:00Z</updated><author><name>万一</name><uri>http://www.cnblogs.com/del/</uri></author><link rel="alternate" href="http://www.cnblogs.com/del/archive/2011/12/31/2308656.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/del/archive/2011/12/31/2308656.html"/><content type="html">&lt;br/&gt;&#xD;
2011 年的最后一天了...&lt;br/&gt;&lt;br/&gt;&#xD;
&#xD;
混合排序 -&gt; 搅乱、重新洗牌; 以 Integer 动态数组为例.&lt;hr/&gt;&lt;br/&gt;&#xD;
&#xD;
&lt;pre &gt;//两个辅助函数 Swap、ToStr, 分别用于交换数组元素和呈现为字符串&#xD;
procedure Swap(var Arr: TArray&amp;lt;Integer&amp;gt;; a,b: Cardinal);&#xD;
var&#xD;
  tmp: Integer;&#xD;
begin&#xD;
  if (a &amp;gt;= Length(Arr)) or (b &amp;gt;= Length(Arr)) or (a = b) then Exit;&#xD;
  tmp := Arr[a];&#xD;
  Arr[a] := Arr[b];&#xD;
  Arr[b] := tmp;&#xD;
end;&#xD;
&#xD;
function ToStr(const Arr: TArray&amp;lt;Integer&amp;gt;): string;&#xD;
var&#xD;
  n: Integer;&#xD;
begin&#xD;
  for n in Arr do&#xD;
    Result := Result + IntToStr(n) + sLineBreak;&#xD;
end;&#xD;
//-----------------------------------------------------------------&#xD;
&#xD;
{1、简单反排序}&#xD;
procedure SimpleShuffle(var Arr: TArray&amp;lt;Integer&amp;gt;);&#xD;
var&#xD;
  r,i: Integer; //分别用作随机索引、遍历索引&#xD;
begin&#xD;
  for i := 0 to Length(Arr) - 1 do&#xD;
  begin&#xD;
    r := Random(Length(Arr));&#xD;
    Swap(Arr, i, r);&#xD;
  end;&#xD;
end;&#xD;
&#xD;
{2、好的反排序}&#xD;
procedure GoodShuffle(var Arr: TArray&amp;lt;Integer&amp;gt;);&#xD;
var&#xD;
  r,i: Integer;&#xD;
begin&#xD;
  for i := Length(Arr) - 1 downto 0 do&#xD;
  begin&#xD;
    r := Random(i + 1);&#xD;
    if r &amp;lt;&amp;gt; i then Swap(Arr, i, r);&#xD;
  end;&#xD;
end;&#xD;
&#xD;
{测试}&#xD;
procedure TForm1.Button1Click(Sender: TObject);&#xD;
var&#xD;
  arr1,arr2: TArray&amp;lt;Integer&amp;gt;;&#xD;
begin&#xD;
  arr1 := TArray&amp;lt;Integer&amp;gt;.Create(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); //&#xD;
  arr2 := Copy(arr1);                                           //&#xD;
&#xD;
//  SimpleShuffle(arr2);&#xD;
  GoodShuffle(arr2);&#xD;
&#xD;
  Memo1.Text := ToStr(arr1);&#xD;
  Memo2.Text := ToStr(arr2);&#xD;
end;&#xD;
&lt;/pre&gt;&lt;hr/&gt;&lt;img src="http://www.cnblogs.com/del/aggbug/2308656.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/del/archive/2011/12/31/2308656.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
