Introduction
Many a times we need to read records from binary files. While reading a record, it is necessary to know the structure of the record. Once we know the structure of the record, it becomes simple to read from the binary file.
But what happens if the structure changes? What happens if the field type in the structure changes? Do we need to write the source code again?
This is what I will try to do in this article. Read a binary file without coding the structure of field type.
Input file
I created a simple binary file with the following record in it:
CUSTOMER_ID 1
CUSTOMER_NAME "MY_CUSTOMER"
ORDER_QTY 100
RATE 10.00
Good old XML CONFIG file
Once we know how the input file looks like, we can re-create the structure as some input to our reader. I decided to use XML. You can use anything that has the flexibility to read all types of data; we also put some Reader method info in the XML. In all the XML looks like this:
<reader_config>
<method_info type="int">ReadInt32</method_info>
<method_info type="double">ReadDouble</method_info>
<method_info type="string">ReadString</method_info>
<method_info type="bool">ReadBoolean</method_info>
<record>
<field_type>int</field_type>
<field_type>string</field_type>
<field_type>int</field_type>
<field_type>double</field_type>
</record>
</reader_config>
The method_info
tag is used to define the type of the field. You can use any name int
, double
, string
, bool
as I have used, or Tom, Dick, and Harry. What is important here is to put the right method to read a particular type. Here, I have put the methods of the class BinaryReader
.
The node record contains the order of fields. For now, I have this for the field_type
property. This can be easily extended to field_name, default values, valid value ranges etc.
public class IBIOReader
First, let us start discussing about the fields:
protected Hashtable method_info_table =
new Hashtable();
protected ArrayList record = new ArrayList();
protected BinaryReader brdr;
protected bool init = false;
The method_info_table
contains the key value pair of the type in method_info
tag and MethodInfo
object of System.Reflection
namespace. The MethodInfo
object contains the BinaryReader
's Read
method to invoke.
The record list contains the field_type
of the record tag.
Public methods
public void Initialize(string i_xml_path)
The parameter i_xml_path
gives the path and name of the file from which to load the reader configuration. Initialize
method populates the record list and the method_info_table
.
In order to populate the method_info_table
, we use the System.Reflection.MethodInfo
class. This is accomplished in the following way:
Type binReaderType =
Type.GetType("System.IO.BinaryReader");
MethodInfo mi = binReaderType.GetMethod(method);
public bool Open(string file_name)
This opens the binary file with the name file_name
. Returns false
, if the Reader is not initialized.
public int ReadNextRecord(ref ArrayList r_record)
The method used to read a particular type is picked up from the method_info_table
. The Invoke
method of the MethodInfo
object is then called. In code form ...
MethodInfo mi = (MethodInfo)method_info_table[s];
object obj = mi.Invoke(brdr, null);
r_record.Add(obj);
reads the next record. r_record
contains the list of objects in the record. The function returns 0 if end of stream is reached, -1 if there is an error and 1 if the read is successful.
public bool Open(string file_name)
Open a file with the name file_name
. Returns false
, if the reader is not initialized.
public void Close()
Close the reader.
In all the methods, exception need to be caught at the previous level.
How to Use?
Here is the sample source code to use this reader:
using IntelliBinIO;
try
{
ArrayList record = new ArrayList();
IBIOReader rdr = new IBIOReader();
rdr.Initialize(@"C:\reader_config.xml");
rdr.Open(@"C:\MYDATA.DAT");
while (rdr.ReadNextRecord(ref record) != 0)
{
Console.WriteLine("Read Record Done! Values are:-");
foreach (object obj in record)
{
Console.WriteLine(obj);
}
}
rdr.Close();
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
Improvements and enhancements
- Allow customized readers.
- Instead of returning an
ArrayList
of objects, create a class called Field
, which has properties like name, value, valid values, type etc.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.