Posts Tagged .NET
.NET StringBuilder — Fast, but not as fast as you think!
Posted by eric in C# Programming, General Programming, Microsoft .NET 3.0 / WinFX, Reverse Engineering on May 28, 2009
I recently ran into a situation where I was tasked to profile some .NET code and do some optimizations anywhere hot spots popped up. I was amazed to find out that one of the BIGGEST offenders in our code block was a simple call to StringBuilder.Append(char). I had to take a step back and scratch my head and wonder if my profiler was confused.
I re-ran some tests using the StopWatch class to hard code some metrics into the application and they also confirmed the findings. What’s up? How could a class that everyone says you can use to your hearts content when it came to string concatenation was failing me?
Turns out, it was a mix of misuse and a common misconception about the StringBuilder Class.
Continue reading “.NET StringBuilder — Fast, but not as fast as you think!” »
Reading ID3 Tags using C#
Posted by eric in C# Programming, General Programming on February 21, 2007
I’m currently working on an application which will read through a directory full of MP3′s downloaded from USENET and then sort them into sub-folders titled after the “Artists – Album” stored within the ID3 tag.
I currently only have code that can read ID3v1 tags but am working on updated code which will allow for ID3v2+ tags to be read as well.
I use a STRUCT to hold the ID3 data and then use a quick little routine to parse the raw byte[] array containing the ID3 data read from the file into my STRUCT.
The STRUCT:
[csharp]
private struct ID3Tag
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] bTagHeader; //0-2
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 30)]
public byte[] bTrackName; //3-32
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 30)]
public byte[] bArtistsName; //33-62
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 30)]
public byte[] bAlbumName; //63-92
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] bYear; //93-96
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 30)]
public byte[] bComment; //97-126
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public byte[] bGenres; //127
}
[/csharp]
Reading the last 128 bytes of the MP3 file into a byte[] array:
[csharp]
private byte[] ReadID3FromFileToByte(string sLocalFile)
{
using (FileStream oFS = new FileStream(sLocalFile, FileMode.Open, FileAccess.Read))
{
using (BinaryReader oBR = new BinaryReader(oFS))
{
oBR.BaseStream.Position = (oFS.Length – 128);
return oBR.ReadBytes((int)oFS.Length);
}
}
}
[/csharp]
The routine used to convert by the byte[] array into the STRUCT:
[csharp]
private ID3Tag ID3BytesToID3Struct(byte[] bRawID3)
{
GCHandle hRawID3 = GCHandle.Alloc(bRawID3, GCHandleType.Pinned);
ID3Tag id3NewTag = (ID3Tag)Marshal.PtrToStructure((hRawID3.AddrOfPinnedObject()), typeof(ID3Tag));
hRawID3.Free();
return id3NewTag;
}
[/csharp]
And the code which brings it all together:
[csharp]
byte[] bFileData = ReadID3FromFileToByte(sMyInputFile);
ID3Tag myID3 = ID3BytesToID3Struct(bFileData);
[/csharp]
I hope this is able to help someone else out in their efforts to read an ID3 tag using C#.
Cheers!
Why does the Microsoft .NET implementation of GZip compression suck?
Posted by eric in General Programming on January 22, 2007
I’ve been working on a self contained patch generator using C#. For the patch data payload, I wanted to use GZip (or deflate) to compress the payload, this way if you generated a patch for a 1MB file, the patch file wouldn’t be +1MB (5 bytes per change).
I did some quick tests to compare compression ratios on a simulated data payload:
Original Uncompressed Payload: 288k
GZipped using System.IO.Compression: 171k
Zipped using WinZip with “Super Fast” Compression: 105k
7-Zipped using 7-Zip with “Maximum” Compression: 61k
I had to do some research and dig into the MSDN libraries before the answer was finally revealed from the horses mouth:
“The compression functionality in DeflateStream and GZipStream is exposed as a stream. Data is read in on a byte-by-byte basis, so it is not possible to perform multiple passes to determine the best method for compressing entire files or large blocks of data. The DeflateStream and GZipStream classes are best used on uncompressed sources of data. If the source data is already compressed, using these classes may actually increase the size of the stream.”
It’s a bit disappointing that Microsoft itself would not recommend it’s own built in compression routine, and even go so far to say that it may “actually increase the size of the stream”. I hope in the upcoming version of .NET 3.0, they address some shortcomings of this area of the framework. Perhaps an exposed method where you can pass a byte[] which can be compressed using multiple passes and Adaptive Huffman Encoding.
I know there are several alternatives out there, such as assemblies which support the ZIP compression format, but wasn’t the goal of .NET to move away from DLL hell?
In the meantime, I’ll probably be sticking with the Microsoft implementation of GZip until I take some time to create my own Huffman encoding routine. I think a good place to start would be this book titled Data Compression: The Complete Reference. I remember thumbing through it once at a Borders book store and thinking it was a really great reference. At the time though, I had no use for such a resource.
Quick note to my readers: I understand that there are plenty of online resources for Adaptive Huffman Encoding and other compression methods using C# that have already been created. Personally, I learn by doing. So when I do my own research and create something from the ground up it really helps me understand how it all works.


