Jalaj

December 22, 2006

Low Level Handling of DBF Files

Filed under: Database, File Formats, FoxPro, Visual Basic — Jalaj @ 12:43 pm

For years I have worked on FoxPro, not just for databases but for low level handling of files also. I used to deal with corrupted databases using low level handling to recover data, which I coded in FoxPro itself. While I will look for old codes in my archive, how about doing it in VB?

I have referred http://www.clicketyclick.dk/databases/xbase/format/dbf.html for the DBF structure.

The DBF contains a Record Header which is followed by the actual records (All terms used here are in reference to the Format Doc mentioned above). The first 32 bytes of the Records Header give details of the database as
File Version No. (byte 0)
Modification Date (bytes 1-3)
No. of Records (bytes 4-7)
Length of Header (bytes 8-9)
Length of each record (bytes 10-11)
Rest of the header are either reserved or are specific to Database Package/Index Condition… We are not touching those areas.

The header is read for above fields, and textboxes are accordingly filled.

Next comes the ‘Field Descriptor Array’, 32 bytes each for describing each field (for total number of field as determined above). A single byte Terminator comes at the end of this array.

Visual FoxPro has added a “Database Container’ of 263 bytes after this section and also falls under the ‘Record Header’.

We have calculated the number of fields in the database as Size of record Header - 32 bytes of top header - 1 byte terminator - 263 bytes (if the DB erlates to Visual FoxPro) and dividing the result with 32.

For each field, the field descriptor array contains
Field Name in ASCII (bytes 0-10)
Field type (ASCII) (byte 11)
Field Offset (bytes 12-15, we would require this only when reading each record)
Field Length (byte 16)
Decimal Count (byte 17)
Rest of the bytes are specific to Database Package, out of scope for now.

We have read 32 bytes at a time for filling each row of the MS-FlexGrid control, thus showing up the Database/Field info. For getting the records we have to read further, may be we take it later.

dbf.jpg

Create a VB Project, add a TextBox named txtFileName, a command button named cmdBrowse and a MS-Common Dialog Control named dlgOpen. This will take care of selection of DBF file.

Add other Textboxes named txtVersionNo, txtModDate, txtNoOfRecords, txtHeaderLength, txtNoOfFields, txtRecordLength and appropriate Labels. Add a MS-FlexGrid Control naming it fgFields.

Lastly add a command button cmdOpen which will execute the reading and parsing code. Just paste the code below and check with DBF files existing in Visual Studio Folder/subfolders.

dbf2.jpg


Private Sub cmdBrowse_Click()

    dlgOpen.DialogTitle = "Select DBF file"
    dlgOpen.Filter = "DBF FIles|*.dbf"
    dlgOpen.DefaultExt = "dbf"

    dlgOpen.ShowOpen
    If Trim(dlgOpen.FileName) <> "" Then
        txtFileName.Text = dlgOpen.FileName
    End If
End Sub

Private Sub cmdOpen_Click()

    Dim objStream As New ADODB.Stream
    Dim lngDBContainer As Long

    objStream.Type = adTypeBinary
    objStream.Open

    objStream.LoadFromFile txtFileName
    byteArray = objStream.Read(32)
    txtVersionNo = byteArray(0)
    txtModDate = DateSerial(byteArray(1) + 1900, byteArray(2), byteArray(3))
    txtNoOfRecords = byteArray(4) + byteArray(5) * 256 + byteArray(6) * 256 ^ 2 + byteArray(7) * 256 ^ 3
    txtHeaderLength = byteArray( 8) + byteArray(9) * 256
    If txtVersionNo = 48 Or txtVersionNo = 49 Then
        lngDBContainer = 263
    Else
        lngDBContainer = 0
    End If
    txtNoOfFields = (txtHeaderLength - 33 - lngDBContainer) / 32
    txtRecordLength = byteArray(10) + byteArray(11) * 256

    With fgFields
        .Clear
        .Rows = txtNoOfFields + 1
        .ColWidth(0) = 3000
        .ColWidth(1) = 1500
        .ColWidth(2) = 1500
        .ColWidth(3) = 1500
        .Width = 7700
        .Row = 0: .Col = 0: .Text = “Field Name”
        .Row = 0: .Col = 1: .Text = “Field Type”
        .Row = 0: .Col = 2: .Text = “Field Length”
        .Row = 0: .Col = 3: .Text = “Field Decimals”

    End With

    For a = 1 To txtNoOfFields
        byteArray = objStream.Read(32)
        For b = 0 To 9
            With fgFields
                .Row = a: .Col = 0: .Text = .Text & Chr(byteArray(b))
            End With
        Next
        With fgFields
            .Row = a: .Col = 1: .Text = Chr(byteArray(11))
            .Row = a: .Col = 2: .Text = byteArray(16)
            .Row = a: .Col = 3: .Text = byteArray(17)
        End With

    Next

    objStream.Close
    Set objStream = Nothing

End Sub

3 Comments »

  1. [...] Low Level Handling of DBF Files [...]

    Pingback by Not a Database File Error in DBF « Jalaj — March 16, 2007 @ 4:07 am

  2. [...] format specification. I got into it and developed a software that recovers files with such errors. Low Level Handling of DBF Files describes the DBF file specification and an application to read DBF file headers. Not a Database [...]

    Pingback by The Blog Revisited - 2 « Jalaj — November 16, 2007 @ 4:49 am

  3. hi
    i wand ne query for like
    the database file in dbf format

    selecting the student on their date of joined to school

    doj is date type

    pls help

    Comment by revanasiddappa K.M. — January 2, 2008 @ 9:13 am

RSS feed for comments on this post. TrackBack URI

Leave a comment

Blog at WordPress.com.