Optimizing data transfer performance

If you recall fromChapter 5, Building Integrated Services, you've built a facility to transfer an account from one device to another via Infrared and Bluetooth. In these cases, you are transferring the dataset as is without any sort of compression. This can lead to slow transfer, especially for larger datasets or larger numbers of records.

Microsoft offers data compression functionality via the System.IO.Compression namespace. The GZipStream class allows you to compress a byte array based on the GZIP standard.

Note

The GZipStream class cannot be used to compress files larger than 4 GB in size.

After compressing data, the GZipStream class does not store the original size of the uncompressed data. You must, therefore, implement your own method to "remember" and store this original size somewhere so that it can be used later during decompression. A common approach is to store this size as the first four bytes of the compressed stream.

Let's take a look at the following code to do this. You can also print the size of the data before and after compression to see the performance difference with and without using GZIP compression. Make the following changes to your SerializeDataset function (highlighted in bold):

public static byte[] SerializeDataset(DataSet Data)
{
StringWriter strWriter = new StringWriter();
string _result;
ASCIIEncoding _encoding = new ASCIIEncoding();
Data.WriteXml(strWriter);
_result = strWriter.GetStringBuilder().ToString();
byte[] _buffer = _encoding.GetBytes(_result);
MessageBox.Show("Buffer length before compression :" +
_buffer.Length.ToString());
//We create a GZipStream object or compression
MemoryStream _stream = new MemoryStream();
GZipStream compressedzipStream = new GZipStream(_stream,
CompressionMode.Compress, true);
//We calculate the uncompressed data length and write it as
//the first four bytes of the stream. We will need this
//length during decompression
int _totalLength = _buffer.Length;
compressedzipStream.Write(BitConverter.GetBytes
(_totalLength), 0, 4);
//We now write the remaining data to the stream
compressedzipStream.Write(_buffer, 0, _totalLength);
compressedzipStream.Close();
_buffer = _stream.ToArray();
MessageBox.Show("Buffer length after compression :" +
_buffer.Length.ToString());
return _buffer;
}

Now, let's take a look at the opposite equivalent. The changes you need to make to the DeserializeDataset method are highlighted in bold in the following code snippet:

public static DataSet DeserializeDataset(byte[] Data)
{
//Use the GZipStream class to decompress the incoming data
MemoryStream _stream = new MemoryStream(Data);
GZipStream compressedzipStream = new GZipStream(_stream,
CompressionMode.Decompress);
//Read the first four bytes from the stream this is the
//size (in bytes) of the rest of the stream
byte[] _totalLength = new byte[4];
compressedzipStream.Read(_totalLength, 0, 4);
int _dataSize = BitConverter.ToInt32(_totalLength, 0);
//Create a byte array that has the exact size of the
//decompressed data, and read from the GZipStream object
byte[] _data = new byte[_dataSize];
compressedzipStream.Read(_data, 0, _dataSize);
compressedzipStream.Close();
//Convert the decompressed stream into a Dataset
ASCIIEncoding _encoding = new ASCIIEncoding();
string _stringData;
_stringData = _encoding.GetString(_data, 0, _data.Length);
StringReader _reader = new StringReader(_stringData);
DataSet _ds = new DataSet();
_ds.ReadXml(_reader);
return _ds;
}

As it is probably tedious to test using two mobile devices running Bluetooth at the same time, you can create a simple form to see the effect of GZIP compression. Create a new form with any name, place a button on this form, and write the following code in the click event of the button:

private void button1_Click(object sender, EventArgs e)
{
DataSet _testSet= new DataSet();
_testSet.Tables.Add (new DataTable("TestTable"));
_testSet.Tables[0].Columns.Add (new DataColumn ("TestCol",
System.Type.GetType ("System.String")));
//Generate 1000 dummy records
for (int i = 0; i <= 1000; i++)
{
DataRow myrow = _testSet.Tables[0].NewRow();
myrow["TestCol"] = "Test";
_testSet.Tables[0].Rows.Add(myrow);
}
//Serialize and compress the dataset
byte[] _testArray= SerializeDataset (_testSet);
//Decompress and deserialize the dataset
_testSet= DeserializeDataset (_testArray);
//Ensure the dataset has been decompressed correctly - show
//the number of records in the decompressed dataset
MessageBox.Show("Total Records: " +
_testSet.Tables[0].Rows.Count.ToString ());
}

If you run this form and click on the button, you will be greeted with this pop-up message box. You can see that the serialized dataset before compression is about 54,081 bytes in size.

Optimizing data transfer performance

After compression you will notice that the length of the data is now 736 bytes. This is about a mere 1.4 percent of the original size of the data!

Optimizing data transfer performance

Tip

To compress or not to compress

GZIP compression works exceptionally well with text-based data. You will get better compression rates with larger text data. In fact, for smaller bits of text data (for example, 500 bytes or less), the compression may even yield sizes larger than the original data itself. You should implement routines in your code to check the size of your input data before deciding whether to run your data through compression or not.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.20.56