yyzhen 发表于 2012-1-11 10:49:29

c语言对FoxBase的dbf文件操作

FoxBASE+数据库语言具有较强的数据组织、管理和检索功能。C语言不仅具有很强的通用程序设计功能,而且很适于处理图形图像、系统程序方面的问题。但总的来说,C语言对大量数据信息的处理不如FoxBASE+语言。如果能在C语言程序中直接调用数据库中的数据,则可充分利用这两种语言的优势。   原来的兰德手持机,如HT-2900对数据库的操作用的是HTbase语言,可以直接对数据表dbf文件操作,很方便。
新出的M73型,芯片是恩智浦的ARM7,lpc2294。操作系统是ucosII.开发完全采用了c语言.编译链接后生成的二进制可执行程序下载到手持机中就可以直接执行。对数据库的dbf文件操作提供了c语言封装好的库函数。以库的形式提供,源代码不可知。有兴趣研究一下。
    要能够用C语言直接存取数据库文件,首先必须搞清楚数据库文件的结构。
  FoxBASE+的数据库文件由两部分组成,第一部分是文件头,其前32个字节是文件的整体描述,接着每32个字节定义一个字段,直到碰到一个0DH(字段描述结束符或称为文件头结束标志)为止;第二部分是实际存放每一个记录的数据部分。前32个字节描述如下: 0
1~3
4~7
8~9
10~11
12~31
1个字节
3个字节
4个字节
2个字节
2个字节
20个字节
03H表示无备注型字段,83H表示有
最后一次修改日期(yy/mm/dd)
.DBF文件的记录数,低字节在前
文件头的长度,低字节在前
记录长度,低字节在前
保留字节


从第32个字节开始到0DH为止是字段描述区,每32个字节定义一个字段,包括字段名、字段类型、字段长度、小数位数等。字段描述的各字节意义如表

起止字节
长  度
含  义

0~10
11
12~15
16
17
18~31
11个字节
1个字节
4个字节
1个字节
1个字节
14个字节
字段名
字段类型(ASCII码)
字段数据在内存中的地址
字段长度(二进制数)
数值字段小数位数(二进制数)
保留字节


    因此,文件头的长度可按下面的公式计算:
  文件头长度=32+(32*定义的字段个数)+1
  在0DH后面,紧接着存放数据记录。记录以定长格式顺序存贮,每个记录的第一个字节是删除标识,有删除标记的记录,该字节是2AH(对应符号“*”),无删除标记的记录,该字节为空格(20H)。每个记录的各字段之间没有分隔符,记录无终止符,各种类型的数据均以ASCII码存放。数据记录之后为一个字节的文尾标识(1AH)。
    按照这个结构就可以对其进行任何操作。但是发现,创建dbf文件时,写入了文件头信息后,虽生成了dbf文件,用foxPro打开后提示不是一个表,说明创建的pdf文件有问题。用UltrEdit打开它,查看它的二进制代码,与一个用foxPro创建的dbf文件做对比,发现少写入了很多信息。dbf文件首先是32个字节的头信息,紧接着是字段描述信息,每个字段描述信息占32个字节,知道0DH,字段描述区结束。后面就开始存储字段的具体数据?错。
发现还要有263个字节的后链信息,现在还不明白这有什么用,但发现没有它建的pdf文件就是错的。所以创建建dbf文件时写入了文件头和字段描述后,紧接着要写入263个0充当后链信息。再写入空格ascII码0x20结束,然后才是字段的数据区。字段数据区的存储也是有规律的。可以根据字段描述区和头文件描述区的信息算出字段数据的地址,然后移动文件指针得到相应字段的数据。

    用C语言直接存取DBF数据库文件的方法
 直接读取DBF数据库记录
  知道了文件头的长度后,要想读取数据库中的记录,可先以“rb”方式打开该数据库文件,然后将文件指针定位于文件头结束标志之后(即第一个记录的开始处),便可逐记录读取该库文件的各记录数据。
 直接更新DBF数据库记录
  如果要更新DBF数据库文件中的某个记录或某个记录中的某字段的内容,可首先用fseek函数将文件指针定位于需修改处,然后用fwrite函数写上新的内容。这里应注意的是,由于DBF数据库中的各记录等长,因而当要写上的新内容不足记录所规定的字节数时,须加空格填满。另外,在对同一数据库进行既读又写的操作时,应以读写二进制方式“rb+”打开该数据库文件。
  对DBF数据库的其它操作
  1.如果要删除DBF数据库中的某记录,可先将要删除记录后面的全部记录读入内存,再将文件指针定位于要删除记录的开始处,之后将读入内存的那些记录重新写回文件中,并将库文件的记录数减1。
  2.如果要在DBF数据库中插入一条记录,可先将文件指针定位于要插入的位置,再将要插入位置后面的全部记录读入内存,然后自插入位置写上(键入)要插入的新记录内容,之后将文件指针移到下一个记录的开始处,把已读入内存的那些记录重新写回文件中,最后将库文件的记录数加1。
  对于这两种操作,由于改变了记录数,因而要注意1AH的位置是否相应地调整了。
下面是示例代码:
头文件信息和字段描述信息的结构体定义:

/*内部字段信息结构   */
typedef struct DBField{
   char          name;   /*字段名*/
   char         type;             /*字段类型*/
   void         *teCh;            /*字段数据地址*/
   unsigned charwidth, deC;       /*字段长度及小数位*/
   char         nul;          /*保留字节*/
}DBFIELD;

/*DBF 文件头结构*/
typedef struct DBFstr {
   unsigned charDBF3;               /*DBASE 数据文件标记*/
   unsigned chardate_n,date_y,date_r; /*年月日变量*/
   unsigned longreCord;               /*记录数变量    */
   unsigned short ldb,lrd;            /*头结构.记录长度变量*/
   char         nul;            /*头结构保留字节变量*/
}DBFSTR;

/* DBF 文件句柄结构 */
typedef struct DBFile {
FILE *fdb;            /*文件指针*/
DBFSTR stru;          /*文件头结构 */
DBFIELD *start;       /*字段结构首指针*/
char fields;          /*字段数*/
}DBFILE;


/*外部字段信息结构   */
struct DBF{
   char         name;   /*字段名变量*/
   char         type;             /*字段类型变量*/
   unsigned charwidth,deC;      /*字段长度及小数位变量*/
};

创建dbf文件函数:
DBFILE *db_Create(char *fname, struct DBF *fd)
{
DBFILE *f,*db_findfile();
int n, i = 0;
if((f = db_findfile()) == NULL) return NULL;
if((f->fields = db_verifield(fd)) == 0) return NULL;
if((f->fields = db_verifield(fd)) == 0) return NULL;
n = sizeof(DBFIELD) * f->fields;
if((f->start = (DBFIELD *)malloc(n)) == NULL) return NULL;
memset(f->start, 0, n);
if((f->fdb = fopen(fname, "w+b")) == NULL){
    free(f->start);
    db_error = 6;
    return NULL;
}
/* 将定义的外部字段信息拷贝到内部字段结构中 */
for(i = 0; i < f->fields; i ++)
{
    strcpy(f->start.name, fd.name);
    f->start.type = fd.type;
    f->start.width = fd.width;
    f->start.deC = fd.deC;
    n += fd.width;
}
/* 初始化文件头结构 */
f->stru.DBF3 = DBFFILE;
f->stru.reCord = 0;
f->stru.ldb = f->fields * 32 + 296;
f->stru.lrd = n + 1;
memset(f->stru.nul, 0, 20);
db_date(&f->stru);
if(!db_writestr(f, 1)){
    db_Close(f, 0);
    remove(fname);
    return NULL;
}
return f;
}
首先是二进制形式创建并打开一个后缀为dbf的文件,写入文件头信息。在函数db_writestr中写入。
int db_writestr(DBFILE *f, int flag)
{
int dbend = DBFSTREND;
int i,tmp=0;
if(fseek(f->fdb, 0l, 0)) return 0;
if(!fwrite(&f->stru, sizeof(DBFSTR), 1, f->fdb)) goto err;
if(flag){
    if(fwrite(f->start, sizeof(DBFIELD), f->fields, f->fdb) != f->fields)
      goto err;
    if(!fwrite(&dbend, 1, 1, f->fdb)) goto err;
}
//写后链信息263字节
for(i=0;i<263;i++)
{
      fwrite(&tmp, 1, 1, f->fdb);            
}
tmp=SPACE;
if(!fwrite(&tmp, 1, 1, f->fdb)) goto err;
return 1;
err:
db_error = 4;
return 0;
}
由于字段的数据区存储在字段区之后,因此用c去创建dbf文件较为麻烦。比如,如果增加了字段,则相应的原来的字段数据则要整体往后移,腾出字段信息的地方。如果之前建好了dbf文件的字段信息,则操作较为简单。直接读取文件头信息,就能依次访问到记录数据。
调用函数先打开文件:
DBFILE *db_use(char *fname)
{
   DBFILE *f,*db_findfile();
if((f = db_findfile()) == NULL) return NULL; /* 数据文件打开数超过 MAXFILES */
if((f->fdb = fopen(fname, "r+b")) == NULL){
    db_error = 2;
    return NULL; /* 文件不存在 */
}
if(!db_getstr(f)){
    fclose(f->fdb);
    f->fdb = NULL;
    return NULL;/* 非 DBASE 数据文件或读文件头信息有错 */
}
return f; /* 返回文件指针 */
}
然后读取文件头信息:
int db_getstr(DBFILE *f)
{
/* 读文件头结构 */
int n=0;
if(!fread(&f->stru, sizeof(DBFSTR), 1, f->fdb) || f->stru.DBF3 != '0')
    goto err;
/* 读字段结构 */
f->fields = db_getfields(f->stru);
if((f->start = (DBFIELD *)malloc(sizeof(DBFIELD) * f->fields)) == NULL)
    goto err;
if(fread(f->start, sizeof(DBFIELD), f->fields, f->fdb) != f->fields)
{
    free(f->start);
    goto err;
}
return 1;
err:
db_error = 3;
return 0;
}
下面是主函数中的测试:
struct DBF dbf;
int main(int argc, char *argv[])
{
DBFILE *f,*f1;
char temp;
char temp1="HELLO";
long int n;
f=db_use("classes.dbf");
if(f!=NULL)
{
    printf("打开成功!\n");         
}
else printf("打开失败!\n");
printf("f->stru.date_n=%d\n",f->stru.date_n);//日期:年
printf("f->stru.date_y=%d\n",f->stru.date_y);//月
printf("f->stru.date_r=%d\n",f->stru.date_r);//日
printf("f->stru.ldb %d\n",f->stru.ldb);//
printf("f->stru.lrd %d\n",f->stru.lrd);//
printf("f->stru.reCord %d\n",f->stru.reCord);//
printf("f->stru.DBF3 %d\n",f->stru.DBF3);//

printf("字段总数目 fields %d\n",f->fields);//字段数目
// printf("f->start->name %s\n",f->start->name);//字段名字1
fseek(f->fdb,f->stru.ldb,SEEK_SET);
fseek(f->fdb,f->stru.ldb+(int)(f->start)->teCh,SEEK_SET);
fread(temp,10,1,f->fdb);
temp=0;
printf("字段名称   %s    %s\n",f->start->name,temp);//
printf("字段类型   type    %c\n",f->start->type);//字段类型
printf("字段长度   width   %d\n",f->start->width);//字段长度
printf("字段小数位 deC   %d\n",f->start->deC);//字段小数位
printf("字段偏移量 teCh    %d\n",(f->start)->teCh);//

// printf("(f->start+1)->name %s\n",(f->start+1)->name);//字段名字2
fseek(f->fdb,f->stru.ldb,SEEK_SET);
fseek(f->fdb,f->stru.ldb+(int)(f->start+1)->teCh,SEEK_SET);
fread(temp,10,1,f->fdb);
temp=0;
printf("%s    %s\n",(f->start+1)->name,temp);//
printf("type    %c\n",(f->start+1)->type);//字段类型
printf("width   %d\n",(f->start+1)->width);//字段长度
printf("deC   %d\n",(f->start+1)->deC);//字段小数位
// printf("(f->start+2)->name %s\n",(f->start+2)->name);//字段名字3
fseek(f->fdb,f->stru.ldb,SEEK_SET);
fseek(f->fdb,f->stru.ldb+(int)(f->start+2)->teCh,SEEK_SET);
fread(temp,10,1,f->fdb);
temp=0;
printf("%s    %s\n",(f->start+2)->name,temp);//
printf("type    %c\n",(f->start+2)->type);//字段类型
printf("width   %d\n",(f->start+2)->width);//字段长度
printf("deC   %d\n",(f->start+2)->deC);//字段小数位
fseek(f->fdb,f->stru.ldb,SEEK_SET);
fseek(f->fdb,f->stru.ldb+(int)(f->start+3)->teCh,SEEK_SET);
fread(temp,10,1,f->fdb);
temp=0;
printf("%s    %s\n",(f->start+3)->name,temp);//
printf("type    %c\n",(f->start+3)->type);//字段类型
printf("width   %d\n",(f->start+3)->width);//字段长度
printf("deC   %d\n",(f->start+3)->deC);//字段小数位
fseek(f->fdb,f->stru.ldb,SEEK_SET);
fseek(f->fdb,f->stru.ldb+(int)(f->start+4)->teCh,SEEK_SET);
fread(temp,10,1,f->fdb);
temp=0;
printf("%s    %s\n",(f->start+4)->name,temp);//
printf("type    %c\n",(f->start+4)->type);//字段类型
printf("width   %d\n",(f->start+4)->width);//字段长度
printf("deC   %d\n",(f->start+4)->deC);//字段小数位
printf("\n*******************************\n");//
fseek(f->fdb,f->stru.ldb,SEEK_SET);
fseek(f->fdb,f->stru.ldb+(int)f->start->teCh+f->stru.lrd,SEEK_SET);
fread(temp,10,1,f->fdb);
temp=0;
printf("%s    %s\n",f->start->name,temp);//
printf("type    %c\n",f->start->type);//字段类型
printf("width   %d\n",f->start->width);//字段长度
printf("deC   %d\n",f->start->deC);//字段小数位
fseek(f->fdb,f->stru.ldb,SEEK_SET);
fseek(f->fdb,f->stru.ldb+(int)(f->start+1)->teCh+f->stru.lrd,SEEK_SET);
fread(temp,10,1,f->fdb);
temp=0;
printf("%s    %s\n",(f->start+1)->name,temp);//
printf("type    %c\n",(f->start+1)->type);//字段类型
printf("width   %d\n",(f->start+1)->width);//字段长度
printf("deC   %d\n",(f->start+1)->deC);//字段小数位
fseek(f->fdb,f->stru.ldb,SEEK_SET);
fseek(f->fdb,f->stru.ldb+(int)(f->start+2)->teCh+f->stru.lrd,SEEK_SET);
fread(temp,10,1,f->fdb);
temp=0;
printf("%s    %s\n",(f->start+2)->name,temp);//
printf("type    %c\n",(f->start+2)->type);//字段类型
printf("width   %d\n",(f->start+2)->width);//字段长度
printf("deC   %d\n",(f->start+2)->deC);//字段小数位
fseek(f->fdb,f->stru.ldb,SEEK_SET);
fseek(f->fdb,f->stru.ldb+(int)(f->start+3)->teCh+f->stru.lrd,SEEK_SET);
fread(temp,10,1,f->fdb);
temp=0;
printf("%s    %s\n",(f->start+3)->name,temp);//
printf("type    %c\n",(f->start+3)->type);//字段类型
printf("width   %d\n",(f->start+3)->width);//字段长度
printf("deC   %d\n",(f->start+3)->deC);//字段小数位
fseek(f->fdb,f->stru.ldb,SEEK_SET);
fseek(f->fdb,f->stru.ldb+(int)(f->start)->teCh+(f->stru.lrd)*2,SEEK_SET);
fread(temp,10,1,f->fdb);
temp=0;
printf("%s    %s\n",(f->start)->name,temp);//
strcpy(dbf.name,temp1);
dbf.type='C';
dbf.width=15;
dbf.deC=0;
f1=db_Create("test.dbf",&dbf);
if(f1!=NULL)
{
    printf("创建成功!\n");         
}
else printf("创建失败!\n");
printf("f1->stru.date_n=%d\n",f1->stru.date_n);//日期:年
printf("f1->stru.date_y=%d\n",f1->stru.date_y);//月
printf("f1->stru.date_r=%d\n",f1->stru.date_r);//日
printf("字段总数目 fields %d\n",f1->fields);//字段数目
printf("f1->start->name %s\n",f1->start->name);//字段名字1
printf("f1->start->type %c\n",f1->start->type);//字段类型
printf("f1->start->width %d\n",f1->start->width);//字段长度
printf("f1->start->deC %d\n",f1->start->deC);//字段小数位
printf("f1->stru.ldb %d\n",f1->stru.ldb);//
printf("f1->stru.lrd %d\n",f1->stru.lrd);//
printf("f1->stru.reCord %d\n",f1->stru.reCord);//
printf("f1->stru.DBF3 %d\n",f1->stru.DBF3);//
n=ftell(f1->fdb);
printf("ftell is %d\n",n);
system("pause");
return 0;
}

dos窗口显示结果为:

打开成功!
f->stru.date_n=12
f->stru.date_y=1
f->stru.date_r=10
f->stru.ldb 456
f->stru.lrd 66
f->stru.reCord 3
f->stru.DBF3 48
字段总数目 fields 5
字段名称   CLASSID    4
字段类型   type    C
字段长度   width   15
字段小数位 deC   0
字段偏移量 teCh    1
CLASSNAME    one
type    C
width   15
deC   0
UNITS    10
type    C
width   15
deC   0
NAME    xiao
type    C
width   10
deC   0
SEX    nan
type    C
width   10
deC   0

*************************
CLASSID    5
type    C
width   15
deC   0
CLASSNAME    ming
type    C
width   15
deC   0
UNITS    8
type    C
width   15
deC   0
NAME    li
type    C
width   10
deC   0
CLASSID    6
创建成功!
f1->stru.date_n=12
f1->stru.date_y=1
f1->stru.date_r=11
字段总数目 fields 1
f1->start->name HELLO
f1->start->type C
f1->start->width 15
f1->start->deC 0
f1->stru.ldb 328
f1->stru.lrd 48
f1->stru.reCord 0
f1->stru.DBF3 48
ftell is 329
请按任意键继续. . .

mangocity 发表于 2012-1-16 09:09:24

为什么不用开源的 sqlite? 比 foxbase 好用多了吧。

farmerzhangdl 发表于 2012-1-16 09:43:15

赞同使用sqlite,内存数据库,速度不是foxbase可以比的,foxbase已经退出历史舞台很久了

yyzhen 发表于 2012-1-16 09:57:48

sqlite,在没操作系统的单片机中呢

smset 发表于 2012-2-27 15:55:43

其实挺好的,sqlite除非在linux系统里面用。

而dbf文件操作,可以在小内存里面跑的很好。


/*描述*/
/* DBASE.C 中包含了:
   对XBASE数据库文件(.dbf) 进行常用操作的系列函数。
*/
#include <stdio.h>
#include <dos.h>
#include <bios.h>
#include <malloc.h>
#include <mem.h>
#include <conio.h>
#include <string.h>
#include <fcntl.h>
#include <io.h>
#include <stdlib.h>
#include <ctype.h>

#include "dbase.hpp"

#define SUCCESS 0
#define FALSE -1

#define DOS


#ifdefWINDOWS
static DBF dbfs;
static int dbf_used={0};
static charxzfl_name;

DBF *Use(char *dbf_name)
{
/*
Inputs: char *dbf_name --- valid xbase file name
Returns: DBF pointer todbasefileifsuccessful
       NULLiffailure
#Description
The Use() funtion opens a xbase file andreturns a
DBF pointer to identify thexbase file. All subsequent
references to the opened xbase file must be using the
pointer until the file is closed. A xbase file can be
opened only once at one time.
*/
        DBF *dbf=NULL;
        unsigned char byte_buf;
        int i,k;
//    dbf=(DBF *)malloc(sizeof(DBF));

        for(k=0;k<30;k++){
       if(dbf_used==0) {
                dbf_used=1;
                dbf=&dbfs;
                break;
       }
        }

        if(dbf==NULL){
           dbf_used=0;
           return NULL;
        }

        if((dbf->dhHandle=fopen(dbf_name,"rb+"))==NULL)
        {
//       free(dbf);
           dbf_used=0;
           return NULL;
       }
        fread(&byte_buf,1,1,dbf->dhHandle);
        if(byte_buf!=0x03&&byte_buf!=0x83)       {
           fclose(dbf->dhHandle);
//       free(dbf);
           dbf_used=0;
           return NULL;
        }
        fread(&byte_buf,1,1,dbf->dhHandle);
        dbf->dhModifyDate.year=(unsigned char)(byte_buf+1900);
        fread(&byte_buf,1,1,dbf->dhHandle);
        dbf->dhModifyDate.month=byte_buf;
    fread(&byte_buf,1,1,dbf->dhHandle);
       dbf->dhModifyDate.day=byte_buf;

    fread(&(dbf->dhRecCount),4,1,dbf->dhHandle);
        fread(&(dbf->dhStruLen),2,1,dbf->dhHandle);

    dbf->dhFieldCount=(dbf->dhStruLen-33)/32;
    fread(&(dbf->dhRecLen),2,1,dbf->dhHandle);
        dbf->dbf_struct=(DBF_STRUCT *)malloc(dbf->dhFieldCount *sizeof(DBF_STRUCT));
    if(dbf->dbf_struct==NULL) {

//       free(dbf);
       dbf_used=0;
           return NULL;
   }

    fseek(dbf->dhHandle,32L,SEEK_SET);
    for(i=0;i<dbf->dhFieldCount;i++)
    {
   fread(dbf->dbf_struct.dhFieldName,11,1,dbf->dhHandle);
   fread(&dbf->dbf_struct.dhFieldType,1,1,dbf->dhHandle);
   fread(&dbf->dbf_struct.dhFieldPos,1,1,dbf->dhHandle);

   fseek(dbf->dhHandle,3L,SEEK_CUR);
   fread(&(dbf->dbf_struct.dhFieldLen),1,1,dbf->dhHandle);
          fread(&(dbf->dbf_struct.dhFieldDec),1,1,dbf->dhHandle);
       fseek(dbf->dhHandle,14L,SEEK_CUR);
    }
        fseek(dbf->dhHandle,1L,SEEK_CUR);
    dbf->dhCurrRec=(char *)malloc(dbf->dhRecLen+1);
    if(dbf->dhCurrRec==NULL) {
       free(dbf->dbf_struct);

//       free(dbf);
       dbf_used=0;
           return NULL;
   }

    if(dbf->dhRecCount>0){
      dbf->dhRecNo=-1;
      fread(dbf->dhCurrRec,dbf->dhRecLen,1,dbf->dhHandle);
      dbf->dhCurrRec=0;
      dbf->dhEof=0;
    }
    else
    { for(i=0;i<dbf->dhRecLen;i++)
          dbf->dhCurrRec=' ';
          dbf->dhCurrRec=0;
                dbf->dhRecNo=0;
          dbf->dhEof=1;
    }
    dbf->dhModify=NO;
    return(dbf);
}
int Close(DBF *dbf)
/*
Inputs: DBF *dbf --- DBF pointer to xbase file
Returns: SUCCESS if successful
       FALSE   if failure
#Description
The Close() function closes a xdbase file
*/
{
int i;
char date_tmp;
if(dbf==NULL){
        return FALSE;
}
if(dbf->dhModify==YES)
{
    fseek(dbf->dhHandle,1L,SEEK_SET);
    date_tmp=(char)(dbf->dhModifyDate.year-1900);
    date_tmp=dbf->dhModifyDate.month;
    date_tmp=dbf->dhModifyDate.day;
    fwrite(date_tmp,3,1,dbf->dhHandle);
    fwrite(&(dbf->dhRecCount),4,1,dbf->dhHandle);
}

for(i=0;i<10;i++){
   if(dbf->dhHandle==dbfs.dhHandle) break;
}

fclose(dbf->dhHandle);
free(dbf->dhCurrRec);
free(dbf->dbf_struct);
//free(dbf);
dbf_used=0;
return SUCCESS;
}
#endif

#ifdef DOS
DBF *Use(char *dbf_name) {
/*
Inputs: char *dbf_name --- valid xbase file name
Returns: DBF pointer todbasefileifsuccessful
       NULLiffailure
The Use() funtion opens a xbase file andreturns a
DBF pointer to identify thexbase file. All subsequent
references to the opened xbase file must be using the
pointer until the file is closed. A xbase file can be
opened only once at one time.
*/
        DBF *dbf=NULL;
        unsigned char byte_buf;
        int i,k;
        dbf=(DBF *)malloc(sizeof(DBF));
        if(dbf==NULL){
           return NULL;
        }

        if((dbf->dhHandle=fopen(dbf_name,"rb+"))==NULL)        {
           free(dbf);
           return NULL;
       }
        fread(&byte_buf,1,1,dbf->dhHandle);
        if(byte_buf!=0x03&&byte_buf!=0x83)       {
           fclose(dbf->dhHandle);
           free(dbf);
           return NULL;
        }
        fread(&byte_buf,1,1,dbf->dhHandle);
        dbf->dhModifyDate.year=(unsigned char)(byte_buf+1900);
        fread(&byte_buf,1,1,dbf->dhHandle);
        dbf->dhModifyDate.month=byte_buf;
        fread(&byte_buf,1,1,dbf->dhHandle);
        dbf->dhModifyDate.day=byte_buf;

        fread(&(dbf->dhRecCount),4,1,dbf->dhHandle);
        fread(&(dbf->dhStruLen),2,1,dbf->dhHandle);

    dbf->dhFieldCount=(dbf->dhStruLen-33)/32;
    fread(&(dbf->dhRecLen),2,1,dbf->dhHandle);
    dbf->dbf_struct=(DBF_STRUCT *)malloc(dbf->dhFieldCount *sizeof(DBF_STRUCT));

    if(dbf->dbf_struct==NULL) {
       fclose(dbf->dhHandle);
       free(dbf);   return NULL;
   }

    fseek(dbf->dhHandle,32L,SEEK_SET);
    for(i=0;i<dbf->dhFieldCount;i++)
    {
   fread(dbf->dbf_struct.dhFieldName,11,1,dbf->dhHandle);
   fread(&dbf->dbf_struct.dhFieldType,1,1,dbf->dhHandle);
   fread(&dbf->dbf_struct.dhFieldPos,1,1,dbf->dhHandle);

   fseek(dbf->dhHandle,3L,SEEK_CUR);
   fread(&(dbf->dbf_struct.dhFieldLen),1,1,dbf->dhHandle);
          fread(&(dbf->dbf_struct.dhFieldDec),1,1,dbf->dhHandle);
       fseek(dbf->dhHandle,14L,SEEK_CUR);
    }
        fseek(dbf->dhHandle,1L,SEEK_CUR);
    dbf->dhCurrRec=(char *)malloc(dbf->dhRecLen+1);
    if(dbf->dhCurrRec==NULL) {
       fclose(dbf->dhHandle);
       free(dbf->dbf_struct);
       free(dbf);   return NULL;
   }

    if(dbf->dhRecCount>0){
      dbf->dhRecNo=-1;
      fread(dbf->dhCurrRec,dbf->dhRecLen,1,dbf->dhHandle);
      dbf->dhCurrRec=0;
      dbf->dhEof=0;
    }
    else
    { for(i=0;i<dbf->dhRecLen;i++)
          dbf->dhCurrRec=' ';
          dbf->dhCurrRec=0;
                dbf->dhRecNo=0;
          dbf->dhEof=1;
    }
    dbf->dhModify=NO;
    return(dbf);
}

int Close(DBF *dbf)
/*
Inputs: DBF *dbf --- DBF pointer to xbase file
Returns: SUCCESS if successful
       FALSE   if failure
#Description
The Close() function closes a xdbase file
*/
{
int i;
char date_tmp;
if(dbf==NULL){
        return FALSE;
}
if(dbf->dhModify==YES)
{
    fseek(dbf->dhHandle,1L,SEEK_SET);
    date_tmp=(char)(dbf->dhModifyDate.year-1900);
    date_tmp=dbf->dhModifyDate.month;
    date_tmp=dbf->dhModifyDate.day;
    fwrite(date_tmp,3,1,dbf->dhHandle);
    fwrite(&(dbf->dhRecCount),4,1,dbf->dhHandle);
}

fclose(dbf->dhHandle);
free(dbf->dhCurrRec);
free(dbf->dbf_struct);
free(dbf);
return SUCCESS;
}

#endif



long Append(DBF *dbf)
/*
Inputs: DBF *dbf --- DBF pointer to xbase file
Returns: current record no.
#Description
The Append() function adds a blank record to the end of xdbase file
*/
{
if(dbf==NULL)
return SUCCESS;

fseek(dbf->dhHandle,0L,SEEK_END);
strset(dbf->dhCurrRec,' ');
dbf->dhCurrRec=0x1a;
fwrite(dbf->dhCurrRec,dbf->dhRecLen+1,1,dbf->dhHandle);

fseek(dbf->dhHandle,-1L,SEEK_END);
dbf->dhCurrRec=0;

dbf->dhModify=YES;
dbf->dhRecNo=++(dbf->dhRecCount);
dbf->dhEof=NO;
return(dbf->dhRecNo);
}

long Write_Record(DBF *dbf,char *newrecn){
/*
Inputs: DBF *dbf --- DBF pointer to xbase file
        char *newrecn --- pointer to ASCIIZ string,
                          which is the content of a record
Returns: current record no.
#Description
The Write_Record() function overwrites a record to the last record of xdbase file
*/

if(dbf==NULL||dbf->dhRecNo==0)
      return SUCCESS;
strncpy(dbf->dhCurrRec,newrecn,dbf->dhRecLen);
fseek(dbf->dhHandle,(dbf->dhRecNo-1)*(dbf->dhRecLen)+dbf->dhStruLen,SEEK_SET);
fwrite(dbf->dhCurrRec,dbf->dhRecLen,1,dbf->dhHandle);
return(dbf->dhRecNo);
}

long Go(DBF *dbf,unsigned long step){
/*
Inputs: DBF *dbf --- DBF pointer to xbase file
        unsigned long step --- the step form the top of the xbase file
Returns: current record no.
#Description
The Go() function moves the current-record-pointer to the record
whoes record no. is step.
*/

if(dbf==NULL||dbf->dhRecNo==0)
   return SUCCESS;
if(step>dbf->dhRecCount){
    dbf->dhRecNo=dbf->dhRecCount;
    dbf->dhEof=1;
   }
else dbf->dhRecNo=step;
fseek(dbf->dhHandle,(dbf->dhRecNo-1)*(dbf->dhRecLen)+dbf->dhStruLen,SEEK_SET);
fread(dbf->dhCurrRec,dbf->dhRecLen,1,dbf->dhHandle);
return(dbf->dhRecNo);
}

char *Read_Record(DBF *dbf,unsigned long step){
/*
Inputs: DBF *dbf --- DBF pointer to xbase file
        unsigned long step --- the step form the top of the xbase file
Returns: Pointer to ASCIIZ string which is the content of the read record
#Description
The Read_Record() function reads the recordwhoesrecord no. is step
*/
if(step>dbf->dhRecCount)
   return("");
else {
   Go(dbf,step);
   return(dbf->dhCurrRec);
}
}

intWrite_In(DBF *dbf,char *buf){
/*
Inputs: DBF *dbf --- DBF pointer to xbase file
        char buf --- Pointer to void string which is the content of the written record
Returns: SUCCESS if successful
       FALSEif failure
#Description
The Write_In() function writes the recordwhoesrecord no. is step
*/

int i,j,str_len=0,rec_bar,buf_bar;
char tmp={0};
char c_value={0};
if(dbf==NULL||dbf->dhRecNo==0)
      return SUCCESS;
tmp=buf;//del_flag
rec_bar=1;buf_bar=1;
for(i=0;i<dbf->dhFieldCount;i++){
//       dbf->dbf_struct.dhFieldType;
//       dbf->dbf_struct.dhFieldDec
       switch(dbf->dbf_struct.dhFieldType){
        case 'C':
           for(j=0;j<dbf->dbf_struct.dhFieldLen;j++)
             tmp=buf;
           if(dbf->dbf_struct.dhFieldLen>1)buf_bar++;
        break;
        case 'N':
           memset(tmp+rec_bar,' ',dbf->dbf_struct.dhFieldLen);
           sprintf(c_value,"%d",*(int *)(buf+buf_bar));
           strcpy(tmp+rec_bar+dbf->dbf_struct.dhFieldLen\
                -strlen(c_value),c_value);
           rec_bar+=dbf->dbf_struct.dhFieldLen;
           buf_bar+=sizeof(int);
        break;
        case 'F':
           memset(tmp+rec_bar,' ',dbf->dbf_struct.dhFieldLen);
           sprintf(c_value,"%.2f",*(float *)(buf+buf_bar));
           strcpy(tmp+rec_bar+dbf->dbf_struct.dhFieldLen\
                -strlen(c_value),c_value);
           rec_bar+=dbf->dbf_struct.dhFieldLen;
           buf_bar+=sizeof(float);
        break;
        case 'L':
           if(*(int *)(buf+buf_bar)==1)tmp='T';
           else tmp='F';
           buf_bar++;
           rec_bar++;
        break;
       }
   }//end for
   for(i=0;i<str_len;i++) if(buf=='\0') buf=' ';
   strncpy(dbf->dhCurrRec,tmp,dbf->dhRecLen);
   fseek(dbf->dhHandle,(dbf->dhRecNo-1)*(dbf->dhRecLen)+dbf->dhStruLen,SEEK_SET);
   fwrite(dbf->dhCurrRec,dbf->dhRecLen,1,dbf->dhHandle);
   return SUCCESS;
}

intRead_Out(DBF *dbf,char *buf,unsigned long step){
/*
Inputs: DBF *dbf --- DBF pointer to xbase file
        char buf --- Pointer to void string ,to get the record content
Returns: SUCCESS if successful
       FALSEif failure
#Description
The Read_Out() function reads the recordwhoesrecord no. is step
*/

int i,k,pos_bar=0,rec_bar=0;
float f;
char tmp={0};

if(step>dbf->dhRecCount || step<1L)
   return FALSE;
else {
   Go(dbf,step);
//   return(dbf->dhCurrRec);
   buf=*(dbf->dhCurrRec+rec_bar++);
   for(i=0;i<dbf->dhFieldCount;i++){
//       dbf->dbf_struct.dhFieldType;
//       dbf->dbf_struct.dhFieldDec
       memset(tmp,'\0',20);
       switch(dbf->dbf_struct.dhFieldType){
        case 'C':
           if(dbf->dbf_struct.dhFieldLen==1)
              buf=*(dbf->dhCurrRec+rec_bar++);
           else {
              for(k=0;k<dbf->dbf_struct.dhFieldLen;k++)
               buf=*(dbf->dhCurrRec+rec_bar++);
              buf='\0';
              for(k=0;k<dbf->dbf_struct.dhFieldLen;k++){
//               if(buf==' ') buf='\0'; //modified by lq ,1997\08\09
//               else break;
              }
           }
       break;
       case 'N':
              for(k=0;k<dbf->dbf_struct.dhFieldLen;k++)
               tmp=*(dbf->dhCurrRec+rec_bar++);
              *(int *)(buf+pos_bar)=atoi(tmp);
              pos_bar+=sizeof(int);
       break;
       case 'F':
                  for(k=0;k<dbf->dbf_struct.dhFieldLen;k++)
               tmp=*(dbf->dhCurrRec+rec_bar++);
              for(k=0;;k++) if(tmp!=' ') break;
              f=atoi(tmp);
              for(k=0;;k++) if(tmp=='.') break;
              k++;
              f+=(tmp-'0')*0.1;
              f+=(tmp-'0')*0.01;
              *(float *)(buf+pos_bar)=f;
              pos_bar+=sizeof(float);
       break;
       case 'L':
               tmp=*(dbf->dhCurrRec+rec_bar++);
               if(tmp=='F') *(int *)(buf+pos_bar)=0;
               else*(int *)(buf+pos_bar)=1;
               pos_bar+=1;
       break;
       default: break;
       }//end switch
   }
}
return SUCCESS;
}


longSkip(DBF *dbf,int step){
/*
Inputs: DBF *dbf --- DBF pointer to xbase file
        int step --- the steps to move from current record.
Returns:the current record no.
#Description
The Skip() function moves the current-record-pointer.
*/

if(dbf==NULL||dbf->dhRecNo==0)
       return SUCCESS;
if(dbf->dhRecNo+step<1)
      step=1-dbf->dhRecNo;
else if(dbf->dhRecNo+step>dbf->dhRecCount)
{
      step=dbf->dhRecCount-dbf->dhRecNo;
      dbf->dhEof=1;
}
dbf->dhRecNo+=step;
if(step!=1)
      fseek(dbf->dhHandle,dbf->dhRecLen*(step-1),SEEK_CUR);
fread(dbf->dhCurrRec,dbf->dhRecLen,1,dbf->dhHandle);
return(dbf->dhRecNo);
}

/*
int MyCopy(char *source,char *dest){
int readlen=4096;
int readcnt;
char ptr={0};
FILE *fp1,*fp2;
fp1=fopen(source,"rb");
if(fp1==NULL) return -1;

fp2=fopen(dest,"wb");
if(fp2==NULL) {
   fclose(fp1);
   return-1;
}
for(;;){
#ifdef MTASk
//... save filepos
tDelay(0);
//... restore filepos
#endif
readcnt=fread(ptr,1,readlen, fp1);
if(readcnt){ fwrite(ptr,1,readcnt,fp2); fflush(fp2);}
if(readcnt!=readlen) break;
}
fclose(fp1); fclose(fp2);
return 0;
}
*/

int MyStrcmp(char *source,char *match){
int i,len;
int retv=0;
len=strlen(match);
for(i=0;i<len;i++){
    if(match=='?') continue;
    if(source==match) continue;
    else { retv=-1;break;}
}
return retv;
}

int Find(DBF *dbf,char *match,int match_pos,long startno,long *recno){
/*
match---match string
match_pos---the start matching position in the record string.
//match_pos=(sun of the previous field lenth)+1
startno---the start recordno in the dbf
recno---the first matched record no in dbf
return --- SUCCESS , FALSE
note: char '?' in match string,indicate that this char is ignored in matching.
*/
   int found=0,i,j;
//   char record={0};
   char *record;

   if(Go(dbf,startno)!=startno) return FALSE;

   record=new char;
   if(!record) {
   printf("\nError: cannot alloc mem,in Find()");
   return FALSE;
   }

   *recno=startno;
   for(i=startno;!eof(dbf);i++){
      strcpy(record,Read_Record(dbf,i));
      Skip(dbf,1);(*recno)=i;
      if(record!=' ') continue;
      if(MyStrcmp(record+match_pos,match)==0)   found=1;
      else found=0;
      if(found) break;
   }

   delete record;

   if(found)return SUCCESS;
   else   return FALSE;
}


--------------
#define recount(dbf) (dbf->dhRecCount)
#define recno(dbf) (dbf->dhRecNo)
#define isdeleted(dbf)(*(dbf->dhCurrRec)=='*')
#define eof(dbf)(dbf->dhEof)
#define field_name(dbf,field_no)((dbf)->dbf_struct[(field_no)-1].dhFieldName)
#define YES 1
#define NO 0

typedef struct {
       int dhType;
       struct date dbModifyDate;
       long dhRecCount;
       unsigned dhStruLen;
       int DhFieldCount;
       int dhRecLen;
       char dhReserved;
} DBFHEAD;

typedef struct {
int dhHandle;
      unsigneddhFileSize;
} DBTHead;

typedef struct {
char dhFieldName;
      chardhFieldType;
      chardhFieldLen;
      chardhFieldDec;
      int   dhFieldPos;
} DBF_STRUCT;

struct dhDate{
unsigned char year;
unsignedchar month;
unsigned char day;
};

typedef struct {
      FILE   *dhHandle;
      structdhDate dhModifyDate;
      long   dhRecCount;
      unsigned int dhStruLen;
      int   dhFieldCount;
      int      dhRecLen;
      DBF_STRUCT *dbf_struct;
      longdhRecNo;
      char   *dhCurrRec;
      int   dhEof;
      int   dhModify;
      }DBF;

typedef struct{
   int handle;
      unsigned long filesize;
      }DBT;
/*
      typedef struct{
      int handle;
      long filesize;
      long node_position;
      long root_position;
      int i_p_node;
      int text_len;
      char *key;
      char key_type;
      intkey_len;
      NODE *node;
      int node_type;
      inti_count;
      long per_node;
      long suc_node;
      NODE *i_front;
      NODE *i_rear;
      NODE *u_curr;
      int update_tag;
   }IDX;
*/
   intWrite_In(DBF *dbf,char *buf);
   intRead_Out(DBF *dbf,char *buf,unsigned long step);
   long Write_Record(DBF *dbf,char *newrecn);
   char *Read_Record(DBF *dbf,unsigned long step);
   DBF*Use(char *);
   intCreate(char *dbf_name,int dhFieldCount,DBF_STRUCT *dbf_stru);
   intClose(DBF *dbf);
   long Go(DBF *dbf,unsigned long step);
   long Delete(DBF *dbf);
   long Recall(DBF *dbf);
   long Skip(DBF *dbf,int step);
   long Append(DBF *dbf);
   intCreateDbf(int flag,char *filename);

   int MyStrcmp(char *source,char *match);
   int Find(DBF *dbf,char *match,int match_pos,long startno,long *recno);

YaoHui 发表于 2012-2-27 16:26:59

SQLITE才是王道

changxiaoqing11 发表于 2013-7-25 21:58:16

关注DBASE

barryliu 发表于 2013-7-26 00:11:18

就是,干嘛不彻底点你干脆用dbase好了
页: [1]
查看完整版本: c语言对FoxBase的dbf文件操作