Compress and Decompress using .net framework and built in GZipStream

I recently had a project in which I wanted to compress log files I was transferring between servers. I did not realize till I did some research that the .NET framework has a nice little library built in for creating GZIP files. While I think the maximum recommended size for using this is 4GIG I am well under that.

Here is my Compress / Decompress methods

byte[] startfile = File.ReadAllBytes("e:\\mylog.log");
byte[] comp = null;
byte[] decom = null;




 



comp = CompressBytes(startfile);
Console.WriteLine(comp.Length.ToString());



decom = Decompress(comp);
Console.WriteLine(decom.Length.ToString());

 


private void Compress(byte[] fileBytes)
{
using(MemoryStream ms = new MemoryStream())
{
using(GZipStream gz = new GZipStream(ms,
                                             CompressionMode.Compress,
                                             true))
{
gz.Write(fileBytes, 0, fileBytes.Length);

gz.Close();
}
}
}

private byte[] Decompress(byte[] fileBytes)
{
int buffer_size = 100;

using(MemoryStream ms = new MemoryStream(fileBytes))
{
using(GZipStream gz = new GZipStream(ms,
                                             CompressionMode.Decompress,
                                             true))
{
byte[] bufferFooter = null;
int readOffset = 0;
int totalBytes = 0;
byte[] finalBuffer = null;
int uncompLength = 0;
int compressedFileLength = fileBytes.Length;

// Get last 4 bytes (footer) as they contain the
// original length of the compressed bytes

// byte array to hold footer value
bufferFooter = new byte[4];

// Set position of MemoryStream end of stream
// minus the 4 bytes needed
ms.Position = ms.Length - 4;

// Fill the bufferFooter with the last 4 bytes
ms.Read(bufferFooter, 0, 4);

// Set Stream back to 0
ms.Position = 0;

// Convert footer bytes to the length.
uncompLength = BitConverter.ToInt32(bufferFooter, 0);

// Set a temporary buffer to hold the uncompressed
// information. We also make it slightly larger to
// ensure everything will fit. We will later trim
// off the unused bytes.
finalBuffer = new byte[uncompLength + buffer_size];

while(true)
{
// Read from stream up to buffer size. Note that return
// value is actual bytes read in case the number filled
// is less than we requested.
int bytesRead = gz.Read(finalBuffer,
                                        readOffset,
                                        buffer_size);

// If no bytes returned we are done
if(bytesRead == 0)
{
break;
}

readOffset += bytesRead;
totalBytes += bytesRead;
}

// Trim off unused bytes based
Array.Resize<byte>(ref finalBuffer, totalBytes);

return finalBuffer;
}
}
}

Calling ASMX .net Web Service using jQuery

Just started to pick up jquery recently and was playing with calling a .net web service from my page. Was really easy once I used Firefox Firebug to do my debugging and figure out some of the variable names to use to access my data.

Here is my final code

Javascript in page

<script type="text/javascript">
$(document).ready(function() {
$.ajax({
type: "POST",
url: "default.asmx/GetCatalog",
cache: false,
contentType: "application/json; charset=utf-8",
data: "{}",
dataType: "json",
success: handleSuccess,
error: handleError
});
});

function handleSuccess(data, status) {
for (var count in data.d) {
$('#bookTitles').html(
' <strong>Book:</strong> ' + data.d[count].BookName +
' <strong>Author:</strong> ' + data.d[count].Author +
                ' <br />');
}

}

function handleError(xmlRequest) {
alert(xmlRequest.status + ' \n\r '
+ xmlRequest.statusText + '\n\r'
+ xmlRequest.responseText);
}
</script>

and the div that I write the content to

<body>
<b>Books List</b>
<div id="bookTitles">
</div>
</body>

and my Web Service and Class Catalog


[WebMethod]
public Catalog[] GetCatalog()
{
Catalog[] catalog = new Catalog[1];
Catalog cat = new Catalog();
cat.Author = "Jim";
cat.BookName ="His Book";
catalog.SetValue(cat, 0);
return catalog;

}

public class Catalog
{
public string Author;
public string BookName;
}

Replacing text in a stream after writing

Recently I responded to a question asked on StackOverflow. The question was "What is the BEST way to replace text in a File using C# / .NET?"

Just by the question you might assume they were wanting to simply replace text in an existing file and of course you could do that by opening the file and looping over it or doing a Replace of content.

Here is the requirements they gave.

Have a text file that is being written to as part of a very large data extract. The first line of the text file is the number of "accounts" extracted.

Because of the nature of this extract, that number is not known until the very end of the process, but the file can be large (a few hundred megs).

What is the BEST way in C# / .NET to open a file (in this case a simple text file), and replace the data that is in the first "line" of text?

So as you can see they are in the process of writing the file, at the end of the write of the file they now know the information they wish to write at the top of the file. So how might we able to go back and write that information without having to open the file again and write the information at the top of the file?

It turns out it is actually fairly simple. One we want to make sure memory utilization is a factor since these files can be very large we probably do not want to open the whole file and prepend text, or do some kind of search and replace on text content that size. So my suggestion is using a stream. Also by using a Stream we can avoid entirely writing the file, then having to open the file again and write the text. StreamWriter has a BaseStream property that provides you access to the base stream object which then allows you to set the position of the stream back to the top and write out the information.

Here is my answer.

private void WriteUsers()
{    
    string userCountString = null;
    ASCIIEncoding enc = new ASCIIEncoding();
    byte[] userCountBytes = null;
    int userCounter = 0;
    
    using(StreamWriter sw = File.CreateText("myfile.txt"))
    {
        // Write a blank line and return
        // Note this line will later contain our user count.
        sw.WriteLine();
        
        // Write out the records and keep track of the count 
        for(int i = 1; i < 100; i++)
        {
            sw.WriteLine("User" + i);
            userCounter++;
        }
        
        // Get the base stream and set the position to 0
        sw.BaseStream.Position = 0;
        
        userCountString = "User Count: " + userCounter;
        
        userCountBytes = enc.GetBytes(userCountString);
    
        sw.BaseStream.Write(userCountBytes, 0, userCountBytes.Length);
    }

}

Seattle .net dotnet user group

Great new user group that is getting started and it is in Seattle. Was hosted at Starbucks who provided a top notch facility for the meeting. About 25 people showed up and  speaker Charles Sterling  gave us a great presentation walking us through the new testing tools in Microsoft Visual Studio Team Systems 2010. 

Highly recommend this to anyone involved in .NET development and located in or around Seattle.

http://seattledotnet.org/

They also have a facebook group

http://www.facebook.com/group.php?gid=78132511486