Delphi: open a zip archive from a stream -> extract to a stream

前端 未结 1 1704
一向
一向 2021-01-02 19:51

Are there any zip components with such features? I need to download a zip archive from the Internet to a stream, then to open the archive from the stream and then to extract

相关标签:
1条回答
  • 2021-01-02 20:07

    The zip file component that is built into XE2 will do this.

    There is an overloaded Open method that receives a TStream as its input parameters.

    To extract individual files you can call an overloaded Read method passing the name of the file that you wish to extract. The extracted file is returned as a new instance of TStream. You can that use CopyFrom on that instance to transfer the extracted file to your stream.

    var
      ZipFile: TZipFile;
      DownloadedStream, DecompressionStream, MyStream: TStream;
      LocalHeader: TZipHeader;
    ...
    ZipFile := TZipFile.Create;
    try
      ZipFile.Open(DownloadedStream, zmRead);
      ZipFile.Read('myzippedfile', DecompressionStream, LocalHeader);
      try
        MyStream.CopyFrom(DecompressionStream, DecompressionStream.Size);
      finally
        DecompressionStream.Free;
      end;
    finally
      ZipFile.Free;
    end;
    

    Note that I've not tested this code, I've just written it based on the source code for TZipFile and the documentation contained in that source code. There may be a few wrinkles in this but if the code behaves as advertised it meets your needs perfectly.


    OK, now I tested it because I was curious. Here's the program that shows that this all works as advertised:

    program ZipTest;
    
    {$APPTYPE CONSOLE}
    
    uses
      System.SysUtils,
      System.Classes,
      System.Zip;
    
    procedure ExtractToFile(
      const ZipFileName: string;
      const ZippedFileIndex: Integer;
      const ExtractedFileName: string
    );
    var
      ZipFile: TZipFile;
      DownloadedStream, DecompressionStream, OutputStream: TStream;
      LocalHeader: TZipHeader;
    begin
      DownloadedStream := TFileStream.Create(ZipFileName, fmOpenRead);
      try
        ZipFile := TZipFile.Create;
        try
          ZipFile.Open(DownloadedStream, zmRead);
          ZipFile.Read(ZippedFileIndex, DecompressionStream, LocalHeader);
          try
            OutputStream := TFileStream.Create(ExtractedFileName, fmCreate);
            try
              OutputStream.CopyFrom(DecompressionStream, DecompressionStream.Size);
            finally
              OutputStream.Free;
            end;
          finally
            DecompressionStream.Free;
          end;
        finally
          ZipFile.Free;
        end;
      finally
        DownloadedStream.Free;
      end;
    end;
    
    begin
      try
        ExtractToFile('C:\desktop\test.zip', 0, 'C:\desktop\out.txt');
      except
        on E: Exception do
          Writeln(E.ClassName, ': ', E.Message);
      end;
    end.
    

    Note that I extracted by index rather than file name since that was more convenient for me. And I used file streams rather than memory streams which I imagine you would use. However, since the TZipFile methods work with TStream I'm sure that the code will work with streams of any form.


    This is the latest in a series of questions about ZIP files. I know that you are using XE2 and I wonder why you seem reluctant to use the built in ZIP class that XE2 provides. I've not seen anything to indicate that it will not fulfil your requirements. In fact, it is precisely this ability to work directly with streams that makes me feel it has sufficient generality for any application.

    0 讨论(0)
提交回复
热议问题