HiveBrain v1.2.0
Get Started
← Back to all entries
snippetcsharpMinor

Reading binary files in XTF format

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
readingformatfilesbinaryxtf

Problem

I have a few thousand binary files that have corresponding structs in them, followed by any number of bytes (this exact number of bytes is given in one of the fields in the structs). I read in data from the binary files to a struct, and assign variables from certain fields in those structs. I was wondering if there is any significant improvement I could make to speed things up, specifically regarding the binary file reading?

Note: I'm reading in 256 bytes at a time to a struct, and in that struct is a number that says how many bytes follow until the next struct. So there isn't a static pattern to the data that I can follow.

```
const int STRUCT_HEADER_SIZE = 256; //256 bytes
const int FILE_HEADER_SIZE = 1024; //1024 bytes

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct STRUCTHEADER
{
//Sample fields
public ushort MagicNumber;
public byte SubChannelNumber;
public ushort NumChansToFollow;

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public ushort[] Reserved1;

public int NumBytesThisRecord; //This value says how many bytes there are total in the current 'packet' which includes this struct header.

public ushort Year;
public byte Month;
public byte Day;
public byte Hour;
}

FileStream stream1;
STRUCTHEADER testStruct = new STRUCTHEADER();
List filePaths = new List();

foreach (string filePath in filePaths) //for each binary file
{
ReadBinaryFile(filePath); //Read the binary file
}

public void ReadBinaryFile(string filePath)
{
try
{
stream1 = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None);
}
catch(Exception ex)
{
}

try
{
stream1.Position = FILE_HEADER_SIZE; //Start stream after the file header

while (stream1.Position (stream1); //read data from binary file into STRUCTHEADER type struct

//assigning fields here
//ex: int year = testStruct.year;

str

Solution

An alternative solution could be a binary reader (see also: this code project article)

Implementation: (I just replaced the 2 try catch blocks with one using):

public static void ReadBinaryReader(string filePath)
{
    using (var stream1 = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None))
    {
        stream1.Position = FILE_HEADER_SIZE; //Start stream after the file header

        using (var reader = new BinaryReader(stream1))
        {
            while (stream1.Position < stream1.Length) //While not at the end of the stream
            {
                var testStruct = FromReader(reader); //read data from binary file into STRUCTHEADER type struct
                stream1.Position += Math.Abs(testStruct.NumBytesThisRecord - STRUCT_HEADER_SIZE); //Advance to the end of current packet
            }
        }
    }
}

private static STRUCTHEADER FromReader(BinaryReader reader)
{
    STRUCTHEADER result = new STRUCTHEADER();
    result.MagicNumber = reader.ReadUInt16();
    result.SubChannelNumber = reader.ReadByte();
    result.NumChansToFollow = reader.ReadUInt16();
    result.Reserved1 = new []
    {
        reader.ReadUInt16(),
        reader.ReadUInt16(),
    };
    result.NumBytesThisRecord = reader.ReadInt32();
    result.Year = reader.ReadUInt16();
    result.Month = reader.ReadByte();
    result.Day = reader.ReadByte();
    result.Hour = reader.ReadByte();
    return result;
}


It is a little bis faster, but not significat... However, if you have to use a binary reader for reading the other content, maybe it is a reasonable alternative to PtrToStructure.

Reading the 6 mb file 60.000 times takes:


PtrToStructure


1) 3791 ms


2) 3807 ms


3) 3794 ms


BinaryReader


1) 3650 ms


2) 3645 ms


3) 3668 ms

Code Snippets

public static void ReadBinaryReader(string filePath)
{
    using (var stream1 = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None))
    {
        stream1.Position = FILE_HEADER_SIZE; //Start stream after the file header

        using (var reader = new BinaryReader(stream1))
        {
            while (stream1.Position < stream1.Length) //While not at the end of the stream
            {
                var testStruct = FromReader(reader); //read data from binary file into STRUCTHEADER type struct
                stream1.Position += Math.Abs(testStruct.NumBytesThisRecord - STRUCT_HEADER_SIZE); //Advance to the end of current packet
            }
        }
    }
}

private static STRUCTHEADER FromReader(BinaryReader reader)
{
    STRUCTHEADER result = new STRUCTHEADER();
    result.MagicNumber = reader.ReadUInt16();
    result.SubChannelNumber = reader.ReadByte();
    result.NumChansToFollow = reader.ReadUInt16();
    result.Reserved1 = new []
    {
        reader.ReadUInt16(),
        reader.ReadUInt16(),
    };
    result.NumBytesThisRecord = reader.ReadInt32();
    result.Year = reader.ReadUInt16();
    result.Month = reader.ReadByte();
    result.Day = reader.ReadByte();
    result.Hour = reader.ReadByte();
    return result;
}

Context

StackExchange Code Review Q#132184, answer score: 7

Revisions (0)

No revisions yet.