Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How can I zip content using a stream?

How To

How can I zip content using a stream?

by  Griffyn  Posted    (Edited  )
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
[ul][li]creating a TAbZipper object[/li]
[li]either writing to it via a TStream, or saving the data I have to disk[/li]
[li]adding the file to the TAbZipper object[/li]
[li]Opening the zipfile from the disk and attach to the e-mail, or send via TCP using a TFileStream[/li][/ul]

Sure, 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:
[b]uses[/b]
  AbZipTyp, AbArcTyp, AbZipPrc;

[b]type[/b]
  TZipStream = [b]class[/b](TAbZipArchive)
  [b]private[/b]
    [b]procedure[/b] ZipHelper(Sender : TObject; Item : TAbArchiveItem; OutStream : TStream);
    [b]procedure[/b] ZipHelperStream(Sender : TObject; Item : TAbArchiveItem; OutStream, InStream : TStream);
  [b]public[/b]
    [b]constructor[/b] CreateFromStream( aStream : TStream; [b]const[/b] ArchiveName : [b]string[/b] ); [b]override[/b];
  [b]end[/b];

[navy][i]{ TZipStream }[/i][/navy]

[b]constructor[/b] TZipStream.CreateFromStream(aStream: TStream;
  [b]const[/b] ArchiveName: [b]string[/b]);
[b]begin[/b]
  [b]inherited[/b];
  DeflationOption := doMaximum;
  CompressionMethodToUse := smDeflated;
  InsertHelper := ZipHelper;
  InsertFromStreamHelper := ZipHelperStream;
[b]end[/b];

[b]procedure[/b] TZipStream.ZipHelper(Sender: TObject; Item: TAbArchiveItem; OutStream: TStream);
[b]begin[/b]
  AbZip(TAbZipArchive(Sender), TAbZipItem(Item), OutStream);
[b]end[/b];

[b]procedure[/b] TZipStream.ZipHelperStream(Sender: TObject; Item: TAbArchiveItem; OutStream, InStream: TStream);
[b]begin[/b]
  [b]if[/b] Assigned(InStream) [b]then[/b]
    AbZipFromStream(TAbZipArchive(Sender), TAbZipItem(Item), OutStream, InStream);
[b]end[/b];

And then use it like this. This example adds data from a TStringStream to an e-mail message as a zip attachment:
Code:
[b]uses[/b]
  IdAttachmentMemory;
[b]procedure[/b] EmailStrings;
[b]var[/b]
  m : TIdMessage;   [navy][i]// Indy e-mail message object
[/i][/navy]  ss : TStringStream;    [navy][i]// to hold data we're going to zip
[/i][/navy]  ms : TMemoryStream;    [navy][i]// temporary stream
[/i][/navy]  z : TZipStream;     [navy][i]// our zip object
[/i][/navy][b]begin[/b]
  m := TIdMessage.Create;
  [b]try[/b]
    [navy][i]{ TODO: populate TIdMessage with From, Subject, etc. }
[/i][/navy]    ss := TStringStream.Create([teal]''[/teal]);
    [b]try[/b]
      [navy][i]{ TODO: populate the TStringStream object with data }
[/i][/navy]      ss.Position := [purple]0[/purple];     [navy][i]// must reposition at beginning of stream
[/i][/navy]      ms := TMemoryStream.Create;    [navy][i]// temporary memory stream
[/i][/navy]      [b]try[/b]
        z := TZipStream.CreateFromStream(ms, [teal]''[/teal]);
        [b]try[/b]
          z.Load;
          z.AddFromStream([teal]'filename.txt'[/teal], ss);   [navy][i]// filename within zip file
[/i][/navy]          z.SaveArchive;
          z.FStream.Position := [purple]0[/purple];
          [b]with[/b] TIdAttachmentMemory.Create(m.MessageParts, z.FStream) [b]do[/b]
            Filename := [teal]'filename.zip'[/teal];   [navy][i]// filename of attachment in e-mail
[/i][/navy]        [b]finally[/b]
          z.Free;
        [b]end[/b];
      [b]finally[/b]
        ms.Free;
      [b]end[/b];
    [b]finally[/b]
      ss.Free;
    [b]end[/b];
    [navy][i]{ TODO: send message }
[/i][/navy]  [b]finally[/b]
    m.Free;
  [b]end[/b];
[b]end[/b];
Register to rate this FAQ  : BAD 1 2 3 4 5 6 7 8 9 10 GOOD
Please Note: 1 is Bad, 10 is Good :-)

Part and Inventory Search

Back
Top