0

I am working on a project in c#. i want to read a binary file of 64k in length which is multiple of 16 bytes. each 16 byte is an event which has the form:

#pragma noalign(trace_record)
typedef struct trace_record
{
 BYTE char tr_id[2]; // 2 bytes
 WORD tr_task;       //2 bytes
 WORD tr_process;    //2 bytes
 WORD tr_varies;     //2 bytes
 KN_TIME_STRUCT tr_time; //8 bytes
} TRACE_RECORD;

i guess using Binaryreader class i can read the file but how to read it by multiples of 16 byte in this form. later i will extract some 16 byte traces for further processing. so I will be thankful for any help. please assume i am beginner in c# :)

omar000
  • 3
  • 3
  • 3
    If the file is in little endian, you can use `BinaryReader.ReadUInt16` etc. to read individual fields. Don't try to read the whole record in a single memory copy. – CodesInChaos Aug 01 '14 at 10:18
  • Related answer: http://stackoverflow.com/questions/8704161/c-sharp-array-within-a-struct/8704873#8704873 – CodesInChaos Aug 01 '14 at 10:27
  • You may want to take a look at http://stackoverflow.com/questions/6918545/how-to-read-byte-blocks-into-struct and http://stackoverflow.com/questions/11909313/using-structs-in-c-sharp-to-read-data – Eugene Podskal Aug 01 '14 at 10:29
  • i think the best way to read/right this kind of data is to serialize it the the file – Redaa Aug 01 '14 at 10:35
  • Create a memory mapped file, then unsafe cast to struct pointers. Same as fread in C. – leppie Aug 01 '14 at 11:37

1 Answers1

1

The simplest working example is below. It can probably be improved though. If you have big-endian data i file, you can use a MiscUtil library for example.

public struct trace_record
{
    // you can create array here, but you will need to create in manually
    public byte tr_id_1; // 2 bytes
    public byte tr_id_2;

    public UInt16 tr_task;       //2 bytes
    public UInt16 tr_process;    //2 bytes
    public UInt16 tr_varies;     //2 bytes
    public UInt64 tr_time; //8 bytes
}

public static List<trace_record> ReadRecords(string fileName)
{
    var result = new List<trace_record>();

    // store FileStream to check current position
    using (FileStream s = File.OpenRead(fileName))
    // and BinareReader to read values
    using (BinaryReader r = new BinaryReader(s))
    {
        // stop when reached the file end
        while (s.Position < s.Length)
        {
            try
            {
                trace_record rec = new trace_record();
                // or read two bytes and use an array instead of two separate bytes.
                rec.tr_id_1 = r.ReadByte();
                rec.tr_id_2 = r.ReadByte();

                rec.tr_task = r.ReadUInt16();
                rec.tr_process = r.ReadUInt16();
                rec.tr_varies = r.ReadUInt16();
                rec.tr_time = r.ReadUInt64();

                result.Add(rec);
            }
            catch
            {
                // handle unexpected end of file somehow.
            }
        }

        return result;
    }
}

static void Main()
{
    var result = ReadRecords("d:\\in.txt");
    // get all records by condition
    var filtered = result.Where(r => r.tr_id_1 == 0x42);

    Console.ReadKey();
}

EDIT: it's probably better to use class instead of struct. See Why are mutable structs “evil”? Classes are more predictable, especially if you are new to C#. And result list will then store only references to objects.

Community
  • 1
  • 1
sasha_gud
  • 1,635
  • 13
  • 18
  • Thanks. It helped me alot. Now how can i access a particular 16 byte record whose first byte ( tr_id_1) is a character 'B' ? – omar000 Aug 01 '14 at 21:31
  • I've updated initial answer to search for all such records using Linq. This may be a bit slow if you have a lot of records. Consider using `for` loop or some kind of caching/indexing during reading records if you know search conditions at the moment of reading file. You can even store data in a database like SQLite. – sasha_gud Aug 02 '14 at 05:42