DBF
DBF是一种数据库文件格式,为早期Foxbase,Dbase,Visual FoxPro等数据库系统所使用的格式。
DBF数据文件由头记录和数据信息两部分构成。
文件头 |
记录1 |
记录2 |
记录3 |
记录4 |
…… |
记录N |
一、头记录
文件头部分的长度是不定长的,它主要对DBF文件作了一些总体说明,其中最主要的是对这个DBF文件的记录项(也就是列名)的信息进行了详细地描述,比如对每个记录项的名称、数据类型、长度等信息都有具体的说明。
头记录又分为文件头以及记录项信息两部分。
(1)文件头
表1:文件头格式
在文件中的位置 |
内容 |
说明 |
0 |
1个字节 |
表示当前的版本信息 |
1-3 |
3个字节 |
表示最近的更新日期,按照YYMMDD格式。 |
4-7 |
1个32位数 |
文件中的记录条数。 |
8-9 |
1个16位数 |
文件头中的字节数。 |
10-11 |
1个16位数 |
一条记录中的字节长度。 |
12-13 |
2个字节 |
保留字节,用于以后添加新的说明性信息时使用,这里用0来填写。 |
14 |
1个字节 |
表示未完成的操作。 |
15 |
1个字节 |
dBASE IV编密码标记。 |
16-27 |
12个字节 |
保留字节,用于多用户处理时使用。 |
28 |
1个字节 |
DBF文件的MDX标识。在创建一个DBF 表时 ,如果使用了MDX 格式的索引文件,那么 DBF 表的表头中的这个字节就自动被设置了一个标志。 当你下次试图重新打开这个DBF表的时候,数据引擎会自动识别这个标志,如果此标志为真,则数据引擎将试图打开相应的MDX 文件。 |
29 |
1个字节 |
Language driver ID. |
30-31 |
2个字节 |
保留字节,用于以后添加新的说明性信息时使用,这里用0来填写。 |
32-X |
(n*32)个字节 |
记录项信息描述数组。n表示记录项的个数。这个数组的结构在表2.8中有详细的解释。 |
X+1 |
1个字节 |
作为记录项终止标识。 |
(2)记录项信息
头记录从第32个字节开始为N个记录项信息组,每个记录项信息组共32位字节。
数据库有多少记录项(列),就有多少个记录项信息组。每个记录项信息组对一个记录项(列)进行描述。
表2:记录项格式
位置 |
内容 |
说明 |
0-10 |
11个字节 |
记录项名称,是ASCII码值。 |
11 |
1个字节 |
记录项的数据类型,是ASCII码值。(B、C、D、G、L、M和N,具体的解释见下表)。 |
12-15 |
4个字节 |
记录中该字段的偏移量。 |
16 |
1个字节 |
记录项长度,二进制型。 |
17 |
1个字节 |
记录项的精度,二进制型。 |
20 |
1个字节 |
工作区ID。 |
21-30 |
10个字节 |
保留字节,用于以后添加新的说明性信息时使用,这里用0来填写。 |
31 |
1个字节 |
MDX标识。如果存在一个MDX 格式的索引文件,那么这个记录项为真,否则为空。 |
表3:记录项数据类型描述:
代码 |
数据类型 |
允许输入的数据 |
B |
二进制型 |
各种字符。 |
C |
字符型 |
各种字符。 |
D |
日期型 |
用于区分年、月、日的数字和一个字符,内部存储按照YYYYMMDD格式。 |
G |
(Generalor OLE) 通用类型 |
各种字符。 |
N |
数值型(Numeric) |
- . 0 1 2 3 4 5 6 7 8 9 |
L |
逻辑型(Logical) |
? Y y N n T t F f (? 表示没有初始化)。 |
M |
(Memo) |
各种字符。 |
Y |
货币型 |
|
F |
浮点型 |
|
I |
整形 |
|
P |
图片 |
|
头记录以终止符(0x0D)结束。
二、数据实体
终止符(0x0D)之后就是N个数据实体组(实体信息)了,每个数据实体组对应数据库中的一行。
(1)删除标记
每组中,第一个字节为删除标记字符,如果删除标记字节为 ASCII 空格 (0x20),则表示该记录未被删除,如果该字节为星号(0x2A),则表示该记录被删除。
(2)数据
从第二个字节开始,数据按照记录项的描述依次排列,之间没有分隔符。
数据实体信息全部用ASCII码形式存放。
表4:数据实体格式
删除标记 | 对应记录项1的数据 | 对应记录项二的数据 | …… | 对应记录项N的数据 |
数据记录以终止符(0x1A)结束。
三、C/C++ 实例代码
以下为DBF格式的C语言版本读取源代码。
#include <string>
#include <sstream>
#include <io.h>
#include <fcntl.h>
#include <process.h>
#include <sys\stat.h>
#include <iostream>
#include <cstring>
#define byte unsigned char
// 常量赋值
#define MaxBuff 200000
#define COLMAX 40
#define ROWMAX 7000
#define STRLEN 20
using namespace std;
// 缓冲区
char buff[MaxBuff];
// 缓冲区下标
char *buffPt,*endPt;
//日期
struct Date{
int year,month,day;
};
// DBF记录项
struct ColStruct
{
char name[STRLEN];
char mod;
int offset;
int len;
int preci;
int workID;
int MDX;
char rows[ROWMAX][STRLEN];
};
//DBF头记录及数据实体
struct DBFstruct
{
int version;
Date date;
int rowNum;
int headSegLen;
int colLen;
int undoPoc;
int possword;
int LagDriID;
int colNum;
int MDX;
ColStruct cols[COLMAX];
bool isDel[ROWMAX];
}nDbf;
int buffLen;
void readHeadSeg();
void readCol();
void readRowData();
/*
读取DBF文件函数,参数为DBF文件路径,
使用此函数读入DBF并初始化.
*/
int getDbfFile(char path[]){
int fid = 0;
_sopen_s(&fid, path ,O_RDONLY | O_BINARY,_SH_DENYNO,_S_IREAD | _S_IWRITE );
if(fid == 0) return 1;
buffLen = _read(fid,buff,MaxBuff);
buffPt = &buff[0] , endPt = &buff[buffLen];
readHeadSeg();
readCol();
readRowData();
return 0;
}
int getInt(){
int tmp = *((int *) buffPt );
buffPt += 4;
return tmp;
}
short getShort(){
short tmp = *((short *) buffPt );
buffPt += 2;
return tmp;
}
byte getByte (){ return *((byte *) buffPt ++ ); }
char getChar(){ return *((char *) buffPt ++ ); }
void dropByte(int len){ buffPt+=len; }
void getString(char *_Dst , int len){
memcpy(_Dst , buffPt , len * sizeof(char) );
buffPt += len;
_Dst[len] = 0;
}
void readHeadSeg(){
nDbf.version = getByte();
nDbf.date.year = getByte();
nDbf.date.month = getByte();
nDbf.date.day = getByte();
nDbf.rowNum = getInt();
nDbf.headSegLen = getShort();
nDbf.colLen = getShort();
dropByte(2);
nDbf.undoPoc = getByte();
nDbf.possword = getByte();
dropByte(12);
nDbf.MDX = getByte();
nDbf.LagDriID = getByte();
dropByte(2);
}
void readCol(){
int i = 0;
for( ;*buffPt != 0x0D; i ++ ){
ColStruct *nCol = &nDbf.cols[i];
getString(nCol->name,11);
nCol->mod = getChar();
nCol->offset = getInt();
nCol->len = getByte();
nCol->preci = getByte();
dropByte(2);
nCol->workID = getByte();
dropByte(10);
nCol->MDX = getByte();
}
nDbf.colNum = i;
dropByte(1);
}
void readRowData(){
for( int i = 0 ;i < nDbf.rowNum ; i++ ){
if(getByte() == 0x2D )
nDbf.isDel[i] = 0;
else
nDbf.isDel[i] = 1;
for( int j = 0 ; j < nDbf.colNum ; j++)
getString( nDbf.cols[j].rows[i] , nDbf.cols[j].len );
}
}
/*
获得对应数据实体信息
参数为: < 数据实体号(也就是行号),记录项名(也就是列名),出口指针 >
_Dst为数组指针,读取到的信息将会写入_Dst数组内
*/
void getValue(int row, char colName[], void *_Dst){
if(row < nDbf.rowNum)
for(int i = 0 ;i < nDbf.colNum ; i++ ){
if( !strcmp(nDbf.cols[i].name , colName) ){
strcpy_s((char *)_Dst, STRLEN ,nDbf.cols[i].rows[row]);
return;
}
}
strcpy_s((char *)_Dst, STRLEN ,"NULL");
}
/*
重载函数——获得对应数据实体信息
参数为: < 数据实体号(行名),记录项号(列号),出口指针 >
_Dst为数组指针,读取到的信息将会写入_Dst数组内
*/
void getValue(int row , int col, void *_Dst){
if( col < nDbf.colNum && row < nDbf.rowNum )
strcpy_s((char *)_Dst, STRLEN, nDbf.cols[col].rows[row]);
else
strcpy_s((char *)_Dst, STRLEN ,"NULL");
}
//获得数据实体总数(行数)
int getColNum() { return nDbf.colNum; }
//获得数据项总数(列数)
int getRowNum() { return nDbf.rowNum; }