I have a flat file generated by a C program. Each record in the file consists of a fixed length header followed by data. The header contains a field indicating the size of the following data. My ultimate goal is to write a C#/.NET program to query this flat file, so I'm looking for the most efficient way to read the file using C#.
I am having trouble finding the .NET equivalent of line 7 in the following code. As far as I can tell, I have to issue multiple reads (one for each field of the header using BinaryReader) and then issue one read to get the data following the header. I'm trying to learn a way to parse a record in two read operations (one read to get the fixed length header and a second read to get the following data).
This is the C code I am trying to duplicate using C#/.NET:
struct header header; /* 1-byte aligned structure (48 bytes) */
char *data;
FILE* fp = fopen("flatfile", "r");
while (!feof(fp))
{
fread(&header, 48, 1, fp);
/* Read header.length number of bytes to get the data. */
data = (char*)malloc(header.length);
fread(data, header.length, 1, fp);
/* Do stuff... */
free(data);
}
This is C structure of the header:
struct header
{
char id[2];
char toname[12];
char fromname[12];
char routeto[6];
char routefrom[6];
char flag1;
char flag2;
char flag3;
char flag4;
char cycl[4];
unsigned short len;
};
I've come up with this C# object to represent the C header:
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi, Size = 48)]
class RouterHeader
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
char[] Type;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
char[] To;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
char[] From;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
char[] RouteTo;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
char[] RouteFrom;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
char[] Flags;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
char[] Cycle;
UInt16 Length;
}
Well, you can use one call to Stream.Read
to read the length (although you need to check the return value to make sure you've read everything you've asked for; you may not get it all in one go) and then another call to Stream.Read
to get the data itself into a byte array (again, looping until you've read anything). Once it's all in memory, you can pick out the appropriate bytes from the buffer to create an instance of your struct (or class).
Personally I prefer to do all of this explicitly rather than using StructLayout
- the latter always feels somewhat brittle to me.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With