DBF structure: a format reference
The format is over forty years old, the specification has split into dialects, and there is no single standard. This page collects what you need to read a file yourself or to understand why someone else's program cannot.
The header: first 32 bytes
| Offset | Size | Contents |
|---|---|---|
| 0 | 1 | format version: 0x03 dBase III, 0x30 Visual FoxPro, 0x83 dBase III with memo |
| 1–3 | 3 | date of last update: year (two digits), month, day |
| 4–7 | 4 | number of records |
| 8–9 | 2 | header length — this is where the data starts |
| 10–11 | 2 | length of one record |
| 28 | 1 | table flags: 0x01 has .cdx, 0x02 has memo, 0x04 belongs to a .dbc |
| 29 | 1 | language driver (code page) |
A useful consequence: the record count can be checked with arithmetic. (file size − header length) ÷ record length should equal the counter. If it does not, the file was truncated or the counter is lying.
Field descriptors
Right after the header come the field definitions, 32 bytes each, followed by a 0x0D byte that marks the end of the list.
Each descriptor holds: the name (11 bytes, zero-padded), the type (1 byte), the field offset (4 bytes), the length (1 byte), the number of decimal places (1 byte) and flags (1 byte). Field names are limited to ten characters for this reason.
dBase Level 7 is a special case: the name takes 32 bytes and the whole descriptor is 48. The two layouts can be told apart structurally — check which one makes the field lengths add up to the record length in the header.
Field types
| Type | Meaning | How it is stored |
|---|---|---|
C | character string | text, padded with spaces on the right |
N, F | number | as text, right-aligned |
D | date | eight characters YYYYMMDD |
L | logical | one character: T, F, Y, N or a space |
M | memo | a block number in an external file |
I | integer | 4 bytes, little-endian |
T | date and time | 8 bytes: a Julian day and milliseconds |
Y | currency | an 8-byte integer, divided by 10,000 |
B | double in Visual FoxPro, memo in dBase | depends on the version — a frequent source of errors |
Numbers stored as text are not an archaism but a feature: N(12,2) holds exactly what you see, with no binary rounding. That is why totals in a DBF do not “drift” the way they do in floating-point formats.
Records and the deletion flag
Records follow one another, all of the same length. The address of any record is a multiplication away, so access to a record is instant.
The first byte of every record is a service byte: a space means the record is active, an asterisk means it is flagged as deleted. More on this in its own article.
Visual FoxPro adds a system field, _NullFlags: a bit mask in which each bit says that the corresponding field holds NULL. Without parsing it, empty values look like zeros and empty strings — and the difference matters.
FAQ
Why is the same type read differently by different tools?
Because of dialects. The classic example is type B: in Visual FoxPro it is a double-precision number, in dBase a reference to a binary memo.
How do I find out the format version?
From the first byte of the file. But the version only names the dialect: whether memo is present is better judged from the actual field types.
What is the .cdx file next to the table for?
It is an index for fast lookup and sorting. Its data duplicates the table, so after editing the table without the index it has to be rebuilt.
Free for personal use. Your file is not uploaded to a server. Windows version — 3.5 MB, no installation: details. Organizations: license.