Tallan's Technology Blog

Tallan's Top Technologists Share Their Thoughts on Today's Technology Challenges

.NET File Compression in Memory

Karl Schwirz

File compression is nothing new to .NET.  However, in many solutions it requires the developer to establish a file folder which they will write the compressed file to and later read from.

This solution cannot work if you want to compress and use the file in memory without writing to disk.  An example of this could be on a server where you don’t particularly want to have random processes writing to and reading files.

Listed below is a solution we came up with for compressing a file in memory. We used an open source library SharpZipLib from sharpDevelop.net.  There are other good options out there that could also be used.  We found that using this library offered the most intuitive solution to creating the archive file.

The result will be a Stream which can be used to send the compressed data to an FTP Site, attach and send in an email, or if you don’t have any restrictions, write to a local folder.

First we will declare a method that reads in a string of data, initialize a MemoryStream and ZipOutputStram.


using ICSharpZipCode.SharpZipLib.Zip;
public static byte[] CompressFile(string fileContents)
        {
            //Initialize memory stream the compressed data will be written to
            using (MemoryStream outMs = new MemoryStream())
            {
                using (ZipOutputStream zipOut = new ZipOutputStream(outMs))
                {
                    ZipEntry ze = new ZipEntry("OriginalMessage.txt");
                    ze.CompressionMethod = CompressionMethod.Deflated;
                    zipOut.PutNextEntry(ze);
                    
                    //Write the string to the to buffer that will be fed into the ZipStream
                    byte[] byteArray = new byte[fileContents.Length]; 
                    int index = 0;
                    foreach (char fileChar in fileContents)
                    {
                        byteArray[index] = (byte)fileChar;
                        index++;
                    }

                    //Write the compressed data to the outMs memory stream
                    zipOut.Write(byteArray, 0, byteArray.Length);
                    zipOut.Finish();
                }
                return outMs.ToArray();
            }
        }

This isn’t much different from other methods out there.  Notice the data is written to a byte array and given to the ZipOutputStream’s compression call which in turn writes the compressed data to a memory stream.  The difference here is when we return an array of the MemoryStream.

The reason we return the array and not the memory stream is because once we exit the scope of the method we will lose the Memory Stream and the data contents.

Once this compression has been done the calling class should then use some sort of stream to finish the desired functionality.  Below is an example of this by attaching the compressed data to an email.

public static void SendTestEmailWithAttachment(byte[] message)
       {
           try
           {
              var emailClient = new SmtpClient("mail.client.com", 25)
                                 {
                                     Credentials = new NetworkCredential("relay.client.com", "")
                                 };

              var sendFrom = new MailAddress("karl.schwirz@tallan.com");
              var sendTo = new MailAddress("karl.schwirz@tallan.com");

              var myMessage = new MailMessage(sendFrom, sendTo)
                               {
                                   Subject = "Test Email for compression",
                                   Body = "Test Email for compression"
                               };

              var ct = new ContentType() {MediaType = MediaTypeNames.Application.Zip, Name = "Sample.zip"};

              var attachfile = new Attachment(new MemoryStream(message), ct);
              myMessage.Attachments.Add(attachfile);

              emailClient.Send(myMessage);
           }
           catch (Exception ex)
           {
               ex.ToString();
               throw;
           }
       }

Here we have a simple SMTP client that takes in the byte array we get from the compression method we developed earlier.  Notice in the attachment we use a MemoryStream to add the compressed data into the email.

While this is a small alteration to most solutions out there, returning the compressed data this way offers the benefit of eliminating overhead associated with writing the data to a folder first, then moving it to its destination by keeping the compression completely in memory.

No comments

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>