ComponentOne Zip for .NET
Zip for .NET Tutorials / Compressing Data in Memory
In This Topic
    Compressing Data in Memory
    In This Topic

    This tutorial shows how you can compress basic data types such as strings and doubles into memory streams, and expand the data back when you read it from the streams. Here is what the final application will look like:


    Step 1: Create the main form.

    Start a new Visual Studio project. From the Toolbox, add the following controls to the form, by performing a drag-and-drop operation or by double-clicking the component:

    Step 2: Add a reference to the C1Zip assembly.

    Go to the Solution Explorer window and click the Show All Files button. Right-click on References, and select the Add Reference menu option. Select the C1.C1Zip assembly from the list, or browse to find the C1.C1Zip.2.dll file.

    Select the Form1.vb tab (Form1.cs for C#) or go to View|Code to open the Code Editor. At the top of the file, add the following statements:

    To write code in Visual Basic

    Visual Basic
    Copy Code
    Imports System.IO
    Imports C1.C1Zip
    

    To write code in C#

    C#
    Copy Code
    using System.IO;
    using C1.C1Zip;
    

    This makes the objects defined in the C1Zip assembly visible to the project and saves a lot of typing.

    Step 3: Add code to compress strings.

    Double-click the Compress String command button, and add the following code to handle the btnCompressString_Click event:

    To write code in Visual Basic

    Visual Basic
    Copy Code
    Private m_CompressedString As Byte()
    Private Sub btnCompressString_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCompressString.Click
         ' Compress the string.
        Dim ticks As Long = DateTime.Now.Ticks
        m_CompressedString = CompressString(textBox1.Text)
         ' Tell the user how long it took.
        Dim ms As Integer
        ms = (DateTime.Now.Ticks - ticks) / TimeSpan.TicksPerMillisecond
        Dim lenBefore As Integer = textBox1.Text.Length * 2 
        Dim lenAfter As Integer = m_CompressedString.Length
        Dim msg As String
        msg = String.Format("Compressed from {0} bytes to " &  "{1} bytes in {2} milliseconds.", lenBefore, lenAfter, ms)
        MessageBox.Show(msg, "Compressed", MessageBoxButtons.OK, MessageBoxIcon.Information)
         ' We can now expand it.
        btnExpandString.Enabled = True
    End Sub
    

    To write code in C#

    C#
    Copy Code
    private byte[] m_CompressedString;
    private void btnCompressString_Click(object sender, EventArgs e)
    {
         // Compress the string.
         long ticks = DateTime.Now.Ticks;
        m_CompressedString = CompressString(textBox1.Text);
         // Tell the user how long it took.
        int ms = (int)((DateTime.Now.Ticks - ticks) / TimeSpan.TicksPerMillisecond);
        int lenBefore = textBox1.Text.Length * 2;
        int lenAfter = m_CompressedString.Length;
        string msg = string .Format("Compressed from {0} bytes to " + "{1} bytes in {2} milliseconds.", lenBefore, lenAfter, ms);
        MessageBox.Show(msg, "Compressed", MessageBoxButtons.OK, MessageBoxIcon.Information);
         // We can now expand it.
        btnExpandString.Enabled = true;
    }
    

    The first main line declares a member variable called m_CompressedString which will be used to hold the compressed data (encoded as a byte array). The second main line calls a utility function CompressString that compresses a given string into a byte array that can later be expanded to restore the original string. The remainder of the code is used to measure how long the compression process took and to show a dialog box with statistics.

    (Note that the lenBefore variable is calculated as the length of the string times two. This is because .NET strings are Unicode, and each character actually takes up two bytes.)

    Add the following code which implements the CompressString function:

    To write code in Visual Basic

    Visual Basic
    Copy Code
    Public Function CompressString(ByVal str As String) As Byte()
         ' Open the memory stream.
        Dim ms As MemoryStream = New MemoryStream()
          ' Attach a compressor stream to the memory stream.
        Dim sw As C1ZStreamWriter = New C1ZStreamWriter(ms)
          ' Write the data into the compressor stream.
        Dim writer As StreamWriter = New StreamWriter(sw)
        writer.Write(str)
          ' Flush any pending data.
        writer.Flush()
          ' Return the memory buffer.
        CompressString = ms.ToArray()
    End Function
    

    To write code in C#

    C#
    Copy Code
    public byte[] CompressString(string str)
    {
         // Open the memory stream.
        MemoryStream ms = new MemoryStream();
         // Attach a compressor stream to the memory stream.
        C1ZStreamWriter sw = new C1ZStreamWriter(ms);
         // Write the data into the compressor stream.
        StreamWriter writer = new StreamWriter(sw);
        writer.Write(str);
         // Flush any pending data.
        writer.Flush();
         // Return the memory buffer.
        return ms.ToArray();
    }
    

    The function starts by creating a new memory stream. This stream will automatically allocate a memory buffer to hold the compressed data.

    Next, the function creates a C1ZStreamWriter object and attaches it to the new memory stream. Any data written to the C1ZStreamWriter object will be compressed and written to the memory stream.

    The C1ZStreamWriter object only supplies the basic Stream methods for writing bytes and byte arrays. To be able to write other basic types such as strings, integers, and so on, we attach a StreamWriter object to the C1ZStreamWriter. Here's a diagram that shows how this works:


    After the StreamWriter is set up, all we need to do is call its Write method to write the string into the compressed memory stream. When done writing, we also call the Flush method to make sure all cached input is written out.

    Finally, the code uses the ToArray method to return the byte array that was created by the memory stream.

    Step 4: Add code to expand strings.

    To expand the string, we need to follow the reverse sequence of steps used to compress. Double-click the Decompress String button, and add the following code to handle the btnExpandString_Click event:

    To write code in Visual Basic

    Visual Basic
    Copy Code
    Private Sub btnExpandString_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExpandString.Click
     
        ' Expand the string.
        Dim ticks As Long = DateTime.Now.Ticks
        TextBox1.Text = ExpandString(m_CompressedString)
     
        ' Tell the user how long it took.
        Dim ms As Integer = (DateTime.Now.Ticks - ticks) / TimeSpan.TicksPerMillisecond
        Dim lenBefore As Integer = m_CompressedString.Length
        Dim lenAfter As Integer = TextBox1.Text.Length * 2
        Dim msg As String
        msg = String.Format("Expanded from {0} bytes to {1} bytes " & "in {2} milliseconds.", lenBefore, lenAfter, ms)
        MessageBox.Show(msg, "Expanded", MessageBoxButtons.OK, MessageBoxIcon.Information)
    End Sub
    

    To write code in C#

    C#
    Copy Code
    private void btnExpandString_Click(object sender, EventArgs e)
    {
     
        // Expand the string.
        long ticks = DateTime.Now.Ticks;
        textBox1.Text = ExpandString(m_CompressedString);
     
        // Tell the user how long it took.
        int ms = (int)((DateTime.Now.Ticks - ticks) / TimeSpan.TicksPerMillisecond);
        int lenBefore = m_CompressedString.Length;
        int lenAfter = textBox1.Text.Length * 2;
        string  msg;
        msg = string .Format("Expanded from {0} bytes to {1} bytes " + "in {2} milliseconds.", lenBefore, lenAfter, ms);
        MessageBox.Show(msg, "Expanded", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }
    

    The main line calls the utility function ExpandString that takes a byte array and returns the original string. Add the following code for the ExpandString function:

    To write code in Visual Basic

    Visual Basic
    Copy Code
    Public Function ExpandString(ByVal buffer As Byte()) As String
         ' Turn buffer into a memory stream.
        Dim ms As MemoryStream = New MemoryStream(buffer)
         ' Attach a decompressor stream to the memory stream.
        Dim sr As C1ZStreamReader = New C1ZStreamReader(ms)
         ' Read uncompressed data.
        Dim reader As StreamReader = New StreamReader(sr)
        ExpandString = reader.ReadToEnd()
    End Function
    

    To write code in C#

    C#
    Copy Code
    public string ExpandString(byte[] buffer)
    {
         // Turn buffer into a memory stream.
        MemoryStream ms = new MemoryStream(buffer);
         // Attach a decompressor stream to the memory stream.
        C1ZStr
        // Read uncompressed data.
        StreamReader reader = new StreamReader(sr);
        return reader.ReadToEnd();
    }
    

    If you run the project now, you can already experiment with string compression and decompression. You can change the text in the text box, or paste new content into it, then compress and expand the string to see how much it compresses.

    Step 5: Add code to compress binary data.

    Compressing binary data is just as easy as compressing strings. The only difference is that instead of attaching a StreamWriter object to the compressor stream, you attach a BinaryWriter object.

    Double-click the Compress Data button and add the following code to handle the btnCompressData_Click event:

    To write code in Visual Basic

    Visual Basic
    Copy Code
    Private m_CompressedData As Byte()
    Private Sub btnCompressData_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCompressData.Click
         ' Open the memory stream.
        Dim ms As MemoryStream = New MemoryStream()
         ' Attach a compressor stream to the memory stream.
        Dim sw As C1ZStreamWriter = New C1ZStreamWriter(ms)
         ' Attach a BinaryWriter to the compressor stream.
        Dim bw As BinaryWriter = New BinaryWriter(sw)
         ' Write a bunch of numbers into the stream.
        Dim i As Integer
        Dim count As Integer = 1000
        bw.Write(count)
        For i = 0 To count - 1
            Dim a As Double = i * Math.PI / 180.0
            bw.Write(i)
            bw.Write(a)
            bw.Write(Math.Sin(a))
            bw.Write(Math.Cos(a))
        Next i
         ' Flush any pending output.
        bw.Flush()
         ' Save the compressed data.
        m_CompressedData = ms.ToArray()
         ' Done.
        Dim msg As String
        msg =String.Format("Generated table with {0} points," & " saved into {1} bytes", count, m_CompressedData.Length)
        Label1.Text = msg
         ' We can now expand it.
        btnExpandData.Enabled = True
    End Sub
    

    To write code in C#

    C#
    Copy Code
    private void btnCompressData_Click(object sender, EventArgs e)
    {
     
           // Open the memory stream.
        MemoryStream ms = new MemoryStream();
         // Attach a compressor stream to the memory stream.
        C1ZStreamWriter sw = new C1ZStreamWriter(ms);
          // Attach a BinaryWriter to the compressor stream.
        BinaryWriter bw = new BinaryWriter(sw);
          // Write a bunch of numbers into the stream.
        int i;
        int count = 1000;
        bw.Write(count);
        for (i = 0 ; i <= count - 1; i++)
        {
            double a = i * Math.PI / 180.0;
            bw.Write(i);
            bw.Write(a);
            bw.Write(Math.Sin(a));
            bw.Write(Math.Cos(a));
        }
          // Flush any pending output.
        bw.Flush();
          // Save the compressed data.
        m_CompressedData = ms.ToArray();
          // Done.
        string  msg;
        msg =string .Format("Generated table with {0} points," +
            " saved into {1} bytes", count, m_CompressedData.Length);
        label1.Text = msg;
          // We can now expand it.
        btnExpandData.Enabled = true;
    }
    

    The code starts by declaring a member variable called m_CompressedData which will be used to hold the compressed data (encoded as a byte array).

    Then it sets up the MemoryStream, C1ZStreamWriter, and BinaryWriter objects as before (the only difference is we're now using a BinaryWriter instead of a StreamWriter).

    Next, the code writes data into the stream using the Write method. The BinaryWriter object overloads this method so you can write all basic object types into streams. Finally, the Flush method is used as before, to make sure any cached data is written out to the compressed stream.

    Step 6: Add code to expand the binary data.

    Expanding the compressed binary data is just a matter of setting up the decompressor stream and reading the data like you would read it from a regular stream.

    Add the following Click event handler code for the Decompress Data command button:

    To write code in Visual Basic

    Visual Basic
    Copy Code
    Private Sub btnExpandData_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExpandData.Click
         ' Open the memory stream on saved data.
        Dim ms As MemoryStream = New MemoryStream(m_CompressedData)
         ' Attach a decompressor stream to the memory stream.
        Dim sr As C1ZStreamReader = New C1ZStreamReader(ms)
         ' Read the uncompressed data.
        Dim i As Integer
        Dim br As BinaryReader = New BinaryReader(sr)
        Dim count As Integer = br.ReadInt32()
        For i = 0 To count - 1
            Dim deg As Integer = br.ReadInt32()
            Dim rad As Double = br.ReadDouble()
            Dim sin As Double = br.ReadDouble()
            Dim cos As Double = br.ReadDouble()
        Next i
         ' Done, tell the user about it.
        Dim msg As String
        msg = String.Format("Read table with {0} points " & "from stream with {1} bytes.", count, m_CompressedData.Length)
        Label1.Text = msg
    End Sub
    

    To write code in C#

    C#
    Copy Code
    private void btnExpandData_Click(object sender, EventArgs e)
    {
         // Open the memory stream on saved data.
        MemoryStream ms = new MemoryStream(m_CompressedData);
         // Attach a decompressor stream to the memory stream.
        C1ZStreamReader sr = new C1ZStreamReader(ms);
         // Read the uncompressed data.
        int i;
        BinaryReader br = new BinaryReader(sr);
        int count = br.ReadInt32();
        for (i = 0 ; i <= count - 1; i++)
        {
            int deg = br.ReadInt32();
            double rad = br.ReadDouble();
            double sin = br.ReadDouble();
            double cos = br.ReadDouble();
        }
         // Done, tell the user about it.
        string  msg;
        msg = string .Format("Read table with {0} points " +
            "from stream with {1} bytes.", count, m_CompressedData.Length);
        label1.Text = msg;
    }
    

    The code reads the data but does not display it. You can step through it in debug mode to make sure the data being read is the same that was written in.

    If you run the project and click the compress/decompress data buttons, you will see that the data is saved in an array with 14,125 bytes. To save this data in a regular stream, it would take [4 + 1000 * (4 + 8 * 3)] = 28,004 bytes. So we compressed it to about half the original size.

    This concludes the Compressing Data in Memory tutorial.