Click here to Skip to main content
11,415,074 members (77,629 online)
Click here to Skip to main content

Paradox database native .NET reader

, 17 Mar 2011 CPOL
Rate this:
Please Sign up or sign in to vote.
Read contents of a Paradox database in pure .NET code without using BDE or other libraries; index support included.

Introduction

If you are working on software which accesses a Paradox database, you are probably using BDE (Borland Database Engine). This article shows how to use Paradox database files and read some data from them directly. You can also use the primary index to find specific records you need. This could be useful if BDE doesn't cooperate with you or there is another reason why you cannot or don't want to use BDE.

Background

Every developer sometimes has to deal with some kind of black-box - piece of technology which is not opened, and can be accessed only from some external interface, but there is a problem - the black-box is quite mysterious to us - one time it works, another time it doesn't, and whatever you do, it seems to be having its own moods. And then I always wish it would be opened so I could debug it, trace into it, and look at its teeth. Are you also a developer who has Reflector between quick links? Then you will probably understand why I started to search for some .NET native Paradox database reader. I couldn't find any, but I have found some Paradox format specifications, so I decided to write one myself and make it public for others who could use it. Many thanks to Randy Beck and Kevin Mitchell for sharing the Paradox internal structure, and because their materials are online, I will focus my efforts to describing my own code.

Paradox splits data to files using database objects - every table has its own file, and every index too. Data files and indexes have very similar structure, so we can handle them both in one class - ParadoxFile. BLOB values are also stored in their own files, but I haven't implemented the structure.

  • ParadoxFile - base class working with common structures from Paradox data files and indexes
  • ParadoxFile.DataBlock - represents one block of data
  • ParadoxFile.FieldInfo - data type of the field
  • ParadoxFile.V4Hdr - structure which is present only in certain Paradox files/versions
  • ParadoxTable - represents table data file
  • ParadoxPrimaryKey - represents table index
  • ParadoxFileType - enum with all file types
  • ParadoxFieldType - enum with all data types
  • ParadoxRecord - represents a data record
  • ParadoxDataReader - standard IDataReader implementation

The index file is, in fact, simply a table with indexes of datablocks and related indexed values. You can read it directly, but I also created a mechanism which browses through the index tree for you and picks up the desired record. You will have nothing more to do but specify a condition which you would like to apply on your data.

  • ParadoxCondition - base class for conditions which can be used for searching in index data
  • ParadoxCondition nested classes - various condition implementations
  • ParadoxCompareOperator - enum with supported compare operators (==, !=, <, <=, >, >=)

Class diagram

Using the code

One way to go is just open a table and start enumerating. This is done by the following piece of code. We will create a ParadoxTable object and use the Enumerate method to traverse through records. Data is retrieved synchronously as needed, so if we stop reading after a few records, no redundant read operations are taken.

var table = new ParadoxTable(dbPath, "zakazky");
var recIndex = 1;
foreach (var rec in table.Enumerate())
{
    Console.WriteLine("Record #{0}", recIndex++);
    for (int i=0; i<table.FieldCount; i++)
    {
        Console.WriteLine("    {0} = {1}", table.FieldNames[i], rec.DataValues[i]);
    }
    if (recIndex > 10) break;
}

There are, of course, scenarios where this simple method will not suffice. Sometimes we also have to read some data in the middle of a large database, so we need to use an index to minimize disk operations. In the next sample, we will use a primary key index to find records with key values in the range between 1750 and 1760. At first, the index file has to be opened, then we will create a condition composed from two compare operations. We can browse data by calling the Enumerate method on the index. In this case, we will use the ParadoxDataReader class with the the IDatareader implementation so we don't need to rewrite a lot of code if we have used BDE before.

var index = new ParadoxPrimaryKey(table, Path.Combine(dbPath, "zakazky.PX"));
var condition =
    new ParadoxCondition.LogicalAnd(
        new ParadoxCondition.Compare(
            ParadoxCompareOperator.GreaterOrEqual, 1750, 0, 0),
        new ParadoxCondition.Compare(
            ParadoxCompareOperator.LessOrEqual, 1760, 0, 0));
var qry = index.Enumerate(condition);
var rdr = new ParadoxDataReader(table, qry);
recIndex = 1;
while (rdr.Read())
{
    Console.WriteLine("Record #{0}", recIndex++);
    for (int i = 0; i < rdr.FieldCount; i++)
    {
        Console.WriteLine("    {0} = {1}", rdr.GetName(i), rdr[i]);
    }
}

Limitations

  • read-only solution
  • not all data types are supported
  • no SQL, LINQ, or other complex queries
  • you should not work with live database during writing

History

  • 1.0 - Initial version
  • 1.1 - Updated Number data type support (thanks, Tonki)
  • 1.2 - Additional data type support (thanks to Mark Kuin, Christopher Erker, and Tonki again)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Petr Bříza
Software Developer (Senior) Petr Bříza
Czech Republic Czech Republic

Freelance .NET developer from Prague, Czech republic. You have a problem - I am the solution.

Visit me at http://petr.briza.net.

Follow on   LinkedIn

Comments and Discussions

 
QuestionDataBlock index Pin
massimo giampieri14-Feb-13 7:47
membermassimo giampieri14-Feb-13 7:47 
QuestionMemoBlob field return only 200 chars Pin
Daniel Cvetanovski4-Feb-13 2:25
memberDaniel Cvetanovski4-Feb-13 2:25 
GeneralMy vote of 5 Pin
Bill Noto7-Jan-13 10:54
memberBill Noto7-Jan-13 10:54 
QuestionGraphic and Binary Pin
Ultimosoftware20-Sep-12 20:38
memberUltimosoftware20-Sep-12 20:38 
GeneralMy vote of 3 Pin
albertoleon16-Sep-12 7:19
memberalbertoleon16-Sep-12 7:19 
BugErrors When Doing A Simple Read Pin
Member 784497824-Aug-12 9:03
memberMember 784497824-Aug-12 9:03 
I am trying to read this simple and short table (http://www.nathanpatel.org/nagawa/053a0017.db) using C# and the following code:

//Path is the full path to the database file
ParadoxTable paraRead = new ParadoxTable(System.IO.Path.GetDirectoryName(path), System.IO.Path.GetFileNameWithoutExtension(path));

foreach (var paraRec in paraRead.Enumerate())
{
      for (int i = 0; i < paraRead.FieldCount; ++i)
      {
            object item = paraRec.DataValues[i];
      }
}

paraRead.Dispose();

and I am getting the same errors on record 67, 177, and 243. And it is the same record every time. I just do not know what to do.
thanks
GeneralRe: Errors When Doing A Simple Read Pin
Member 784497824-Aug-12 9:09
memberMember 784497824-Aug-12 9:09 
GeneralRe: Errors When Doing A Simple Read Pin
Wilhelm, Michael8-Mar-15 2:05
memberWilhelm, Michael8-Mar-15 2:05 
QuestionA problem reading numbers Pin
Member 926798826-Jul-12 4:57
memberMember 926798826-Jul-12 4:57 
QuestionEncoding support Pin
Member 909365012-Jun-12 7:48
memberMember 909365012-Jun-12 7:48 
QuestionBugs while reading currency values Pin
chanloongloo28-May-12 21:13
memberchanloongloo28-May-12 21:13 
AnswerRe: Bugs while reading currency values Pin
clbyrne9-Feb-14 7:00
memberclbyrne9-Feb-14 7:00 
QuestionBoolean Support? Pin
MKruluts21-May-12 5:26
memberMKruluts21-May-12 5:26 
AnswerRe: Boolean Support? Pin
MKruluts21-May-12 6:05
memberMKruluts21-May-12 6:05 
BugBugs or inconsistent data? asking for help. [modified] Pin
jonnyqqq21-May-12 4:16
memberjonnyqqq21-May-12 4:16 
GeneralMy vote of 5 Pin
Andez200426-Apr-12 1:15
memberAndez200426-Apr-12 1:15 
GeneralRe: My vote of 5 Pin
Andez200426-Apr-12 1:59
memberAndez200426-Apr-12 1:59 
QuestionHow to identify which fields are part of Primary key? [modified] Pin
fastcom12322-Feb-12 12:22
memberfastcom12322-Feb-12 12:22 
QuestionReading encrypted table data Pin
Groffy17-Jan-12 5:25
memberGroffy17-Jan-12 5:25 
QuestionEncoding issue (Argument Exception: Char Buffer too small) Pin
Ben Schowe15-Sep-11 6:46
memberBen Schowe15-Sep-11 6:46 
GeneralBugs when using indexes to read Pin
Joao Teixeira Soares11-Apr-11 20:18
memberJoao Teixeira Soares11-Apr-11 20:18 
GeneralBug in Method ParadoxFile.GetString Pin
Member 12328763-Feb-11 0:45
memberMember 12328763-Feb-11 0:45 
GeneralRe: Bug in Method ParadoxFile.GetString Pin
Guldil3-Feb-11 10:39
memberGuldil3-Feb-11 10:39 
GeneralRe: Bug in Method ParadoxFile.GetString Pin
Member 12328763-Feb-11 21:44
memberMember 12328763-Feb-11 21:44 
GeneralRe: Bug in Method ParadoxFile.GetString Pin
Christopher Erker9-Feb-11 11:28
memberChristopher Erker9-Feb-11 11:28 
GeneralRe: Bug in Method ParadoxFile.GetString Pin
Petr Bříza16-Mar-11 21:41
memberPetr Bříza16-Mar-11 21:41 
GeneralRe: Bug in Method ParadoxFile.GetString Pin
clbyrne9-Feb-14 7:19
memberclbyrne9-Feb-14 7:19 
GeneralI think I do it for suballocated data type (type 3) Pin
kaiserssosse20-Jan-11 22:33
memberkaiserssosse20-Jan-11 22:33 
GeneralRe: I think I do it for suballocated data type (type 3) Pin
kaiserssosse9-Feb-11 22:34
memberkaiserssosse9-Feb-11 22:34 
QuestionAny advance with BLOB? Pin
kaiserssosse16-Jan-11 23:23
memberkaiserssosse16-Jan-11 23:23 
AnswerRe: Any advance with BLOB? Pin
kaiserssosse19-Jan-11 2:08
memberkaiserssosse19-Jan-11 2:08 
AnswerRe: Any advance with BLOB? Pin
Christopher Erker24-Jan-11 3:25
memberChristopher Erker24-Jan-11 3:25 
GeneralRe: Any advance with BLOB? Pin
kaiserssosse24-Jan-11 3:46
memberkaiserssosse24-Jan-11 3:46 
GeneralRe: Any advance with BLOB? Pin
Christopher Erker24-Jan-11 5:26
memberChristopher Erker24-Jan-11 5:26 
GeneralRe: Any advance with BLOB? Pin
kaiserssosse24-Jan-11 22:03
memberkaiserssosse24-Jan-11 22:03 
GeneralRe: Any advance with BLOB? Pin
Goran _23-Nov-12 17:33
memberGoran _23-Nov-12 17:33 
AnswerRe: Any advance with BLOB? Pin
viliam16-Aug-11 11:55
memberviliam16-Aug-11 11:55 
GeneralOverflow bug + solution [modified] Pin
Christopher Erker1-Jan-11 7:26
memberChristopher Erker1-Jan-11 7:26 
GeneralRe: Overflow bug + solution Pin
kaiserssosse17-Jan-11 1:52
memberkaiserssosse17-Jan-11 1:52 
GeneralRe: Overflow bug + solution Pin
Zodraz27-Jan-11 11:29
memberZodraz27-Jan-11 11:29 
GeneralRe: Overflow bug + solution Pin
Petr Bříza16-Mar-11 22:01
memberPetr Bříza16-Mar-11 22:01 
GeneralRe: Overflow bug + solution Pin
SDMX211-Jul-11 23:15
memberSDMX211-Jul-11 23:15 
GeneralRe: Overflow bug + solution [modified] Pin
Goran _26-Aug-12 13:31
memberGoran _26-Aug-12 13:31 
Generalfile format Pin
Peter1537423-Dec-10 5:56
memberPeter1537423-Dec-10 5:56 
GeneralRe: file format Pin
kaiserssosse19-Jan-11 3:17
memberkaiserssosse19-Jan-11 3:17 
Generalnumeric values Pin
Tonki14-Sep-10 6:37
memberTonki14-Sep-10 6:37 
GeneralRe: numeric values Pin
Petr Bříza17-Sep-10 2:17
memberPetr Bříza17-Sep-10 2:17 
GeneralRe: numeric values Pin
Tonki18-Oct-10 3:26
memberTonki18-Oct-10 3:26 
GeneralRe: numeric values Pin
Petr Bříza16-Mar-11 22:08
memberPetr Bříza16-Mar-11 22:08 
QuestionDo you plan on implementing the BLOB structure? Pin
elemeht1-Sep-10 13:01
memberelemeht1-Sep-10 13:01 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150427.4 | Last Updated 17 Mar 2011
Article Copyright 2010 by Petr Bříza
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid