Parse a dbf file by hand, and you learn the format gives up its contents in a strict, predictable order. There are no delimiters between records, no tags marking where fields begin, and no schema stored off in a separate file. Everything a program needs is packed into the opening bytes, split across a header, the data records, and a one-byte end-of-file marker. For a developer writing an importer or a migration script, that layout is the difference between clean extraction and a column of garbage.
Reading the File Header
The header opens at byte zero with a version byte identifying the dialect, whether dBASE III, dBASE IV, or a variant carrying a memo file, which its high bit flags. Next come a three-byte last-update date in YYMMDD form, a four-byte record count, a two-byte header length, and a two-byte record length. Those last two numbers are what a parser depends on most. The header length says where the record data starts, and the record length says how many bytes to advance for each row. Trust the header-length offset when locating the first record, because some versions leave a gap after the descriptors that a hand calculation misses.
The Field Descriptor Array
A 32-byte field descriptor follows for each column, closed by a carriage-return byte (0x0D). Every descriptor defines one column’s identity and shape.
- Field name. The first 11 bytes hold the name in ASCII, zero-filled, capping names at ten usable characters and explaining the terse naming in older tables.
- Field type. Byte 11 carries an ASCII character: C for character, N for numeric, D for date, L for logical, M for memo, F for float.
- Length and decimals. Byte 16 gives the field length in binary and byte 17 the decimal count, together fixing how many bytes the field occupies and how a number reads.
Sum the field lengths, add one byte for the deletion flag, and you get the record length stored in the header. When the two disagree, the file is corrupt or came from a tool that broke the specification.
How Records Are Stored
Each record opens with a deletion flag: a space (0x20) means live, an asterisk (0x2A) means deleted. New parsers often miss this because deleted records stay in the file and only carry the flag, so a reader that ignores it returns rows the database considers gone. Values follow with no separators, each occupying the width its descriptor declared. Character fields cap at 254 bytes, so longer text moves to memo fields, which hold a pointer into a companion DBT file. Copy the DBF but leave the DBT behind, and every memo field comes back a broken reference, a quiet way for legacy imports to lose data.
Where This Knowledge Pays Off
Knowing the layout lets a developer diagnose why a file won’t open, spot a dialect the parsing library can’t handle, or confirm an export preserved field types. For teams that would sooner inspect these files than write a parser from scratch, DBF2002.com offers DBF Viewer 2000, which reads the structure described here and exposes field types, record counts, and deleted-record flags by opening the file, across the dBASE, FoxPro, and Clipper dialects that differ in exactly these header details.
The Payoff of Knowing the Layout
A dbf file rewards developers who understand its internals, because almost every import problem traces back to a detail above: a misread header offset, an ignored deletion flag, a field parsed at the wrong width, or a memo pointer with no DBT behind it. When you would sooner confirm those details than debug a parser blind, DBF Viewer 2000 from DBF2002.com opens the file and shows its structure at a glance. Download the free trial at the site, and the next stubborn dbf file becomes something you can read before writing a line of code.