Ralf Westphal Archiv

weblogs.asp.net

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

19. März 2006Erstveröffentlichung: weblogs.asp.net/ralfwOriginaladresseralfw.de/archiv/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!

← Zurück ins Archiv