Click here to Skip to main content
15,886,080 members
Articles / Programming Languages / C#
Article

Intelligent Binary File Reader

Rate me:
Please Sign up or sign in to vote.
3.69/5 (21 votes)
24 Jul 20053 min read 58.8K   709   23   3
Reads binary records. If the record structure changes, you don't need to change the source code.

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:

XML
<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:

C#
// 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:

    C#
    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 ...

    C#
    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:

C#
using IntelliBinIO;
try
{
 ArrayList record = new ArrayList();
 IBIOReader rdr = new IBIOReader();
 // initialize
 rdr.Initialize(@"C:\reader_config.xml");
 // open file
 rdr.Open(@"C:\MYDATA.DAT");
 // read each record
 while (rdr.ReadNextRecord(ref record) != 0)
 {
  Console.WriteLine("Read Record Done! Values are:-");
  foreach (object obj in record)
  {
   Console.WriteLine(obj);
  }
 }
 // close file
 rdr.Close();
}
catch(Exception e)
{
 Console.WriteLine(e.Message);
}

Improvements and enhancements

  1. Allow customized readers.
  2. Instead of returning an ArrayList of objects, create a class called Field, which has properties like name, value, valid values, type etc.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralArticle Needs Update Pin
coloncm28-Sep-07 9:34
coloncm28-Sep-07 9:34 
GeneralAfter Update Pin
Bothe16-Jul-07 0:32
Bothe16-Jul-07 0:32 
QuestionWhy are you guys rating this article 1? Pin
mav.northwind26-Jul-05 20:23
mav.northwind26-Jul-05 20:23 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.