Deranged Ramblings

Sunday, March 19, 2006

 

Even easier high speed reading/writing of binary data files with C#

In my previous posting I presented a way to avoid unnecessarily copying data during read/write of binary files by using low level C CTR file functions like fread() instead of System.IO. This works just fine - but requires you to link in an unmanaged code C DLL if not even doing programming in C yourself.

Now, thanks to Christof Sprenger at Microsoft Germany, this hurdle has been removed. He showed me how to use the existing low level file handle of a stream with the kernel32.dll ReadFile()/WriteFile() functions. No more C programming is necessary, although unsafe code is still needed. But that´s ok, I´d say.

Here´s an example how simple your code is if you use the new BinaryFileStream class:

struct ID3v1Tag
{
...
};

ID3v1Tag tag;

BinaryFileStream bfs = new BinaryFileStream("track01.mp3", System.IO.FileMode.Open);

bfs.Seek(-128, System.IO.SeekOrigin.End);
unsafe
{
bfs.Read(&tag);
}

tag.Title = ...;
...
bfs.Write(&tag);

bfs.Close();

And here´s the BinaryFileStream itself:

using System.Runtime.InteropServices;

namespace System.IO
{
public unsafe class BinaryFileStream : FileStream
{
#region CTORs

public BinaryFileStream(string path, FileMode mode)
: base(path, mode)
{}

public BinaryFileStream(string path, FileMode mode, FileAccess access)
: base(path, mode, access)
{}

public BinaryFileStream(string path)
: base(path, FileMode.Open)
{ }

#endregion


public int Read(void* buffer) where StructType : struct
{
return Read(buffer, Marshal.SizeOf(typeof(StructType)));
}


public void Write(void* buffer) where StructType : struct
{
Write(buffer, Marshal.SizeOf(typeof(StructType)));
}


#region Low-level file access

protected int Read(void* buffer, int count)
{
int n = 0;

if (!ReadFile(this.SafeFileHandle, buffer, count, out n, 0))
throw new IOException(string.Format("Error {0} reading from file!", Marshal.GetLastWin32Error()));

return n;
}

protected void Write(void* buffer, int count)
{
int n = 0;

if (!WriteFile(this.SafeFileHandle, buffer, count, out n, 0))
throw new IOException(string.Format("Error {0} writing to file!", Marshal.GetLastWin32Error()));
}


[DllImport("kernel32", SetLastError = true)]
private static extern unsafe bool ReadFile(
Microsoft.Win32.SafeHandles.SafeFileHandle hFile,
void* pBuffer,
int numberOfBytesToRead,
out int numberOfBytesRead,
int overlapped
);

[DllImport("kernel32.dll", SetLastError = true)]
private static extern unsafe bool WriteFile(
Microsoft.Win32.SafeHandles.SafeFileHandle handle,
void* bytes,
int numBytesToWrite,
out int numBytesWritten,
int overlapped
);

#endregion
}
}

Copy and enjoy!

Comments: Post a Comment



<< Home

Archives

February 2005   March 2005   December 2005   February 2006   March 2006   July 2006  

This page is powered by Blogger. Isn't yours?

My Photo
Name: