DBF文件格式

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; }


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值