Mega Code Archive

 
Categories / Delphi / Examples
 

How can I zip content using a stream

Title: How can I zip content using a stream? I'm surprised how often I've wanted to be able to do this in different situations: I have data in memory that I want to compress and send via e-mail or via TCP. Using the freeware Abbrevia compression toolkit (http://sourceforge.net/projects/tpabbrevia/), this can be accomplished by creating a TAbZipper objecteither writing to it via a TStream, or saving the data I have to diskadding the file to the TAbZipper objectOpening the zipfile from the disk and attach to the e-mail, or send via TCP using a TFileStreamSure, that works... but it's a tad inefficient. Why is the filesystem getting involved at all? Unfortunately, the Abbrevia toolkit doesn't seem to offer a way to work only with TMemoryStream objects. But I found a way. First up, create yourself a descendant of TABZipArchive: CODE uses AbZipTyp, AbArcTyp, AbZipPrc; type TZipStream = class (TAbZipArchive) private procedure ZipHelper(Sender : TObject; Item : TAbArchiveItem; OutStream : TStream); procedure ZipHelperStream(Sender : TObject; Item : TAbArchiveItem; OutStream, InStream : TStream); public constructor CreateFromStream( aStream : TStream; const ArchiveName : string ); override ; end ; { TZipStream } constructor TZipStream.CreateFromStream(aStream: TStream; const ArchiveName: string ); begin inherited ; DeflationOption := doMaximum; CompressionMethodToUse := smDeflated; InsertHelper := ZipHelper; InsertFromStreamHelper := ZipHelperStream; end ; procedure TZipStream.ZipHelper(Sender: TObject; Item: TAbArchiveItem; OutStream: TStream); begin AbZip(TAbZipArchive(Sender), TAbZipItem(Item), OutStream); end ; procedure TZipStream.ZipHelperStream(Sender: TObject; Item: TAbArchiveItem; OutStream, InStream: TStream); begin if Assigned(InStream) then AbZipFromStream(TAbZipArchive(Sender), TAbZipItem(Item), OutStream, InStream); end ; And then use it like this. This example adds data from a TStringStream to an e-mail message as a zip attachment: CODE uses IdAttachmentMemory; procedure EmailStrings; var m : TIdMessage; // Indy e-mail message object ss : TStringStream; // to hold data we're going to zip ms : TMemoryStream; // temporary stream z : TZipStream; // our zip object begin m := TIdMessage.Create; try { TODO: populate TIdMessage with From, Subject, etc. } ss := TStringStream.Create( '' ); try { TODO: populate the TStringStream object with data } ss.Position := 0 ; // must reposition at beginning of stream ms := TMemoryStream.Create; // temporary memory stream try z := TZipStream.CreateFromStream(ms, '' ); try z.Load; z.AddFromStream( 'filename.txt' , ss); // filename within zip file z.SaveArchive; z.FStream.Position := 0 ; with TIdAttachmentMemory.Create(m.MessageParts, z.FStream) do Filename := 'filename.zip' ; // filename of attachment in e-mail finally z.Free; end ; finally ms.Free; end ; finally ss.Free; end ; { TODO: send message } finally m.Free; end ; end ;