修复FOXPRO25数据库
戴立群
作为一个FOXPRO程序员或数据库维护人员,当碰到数据库损坏 的情况时,肯定会非常恼火,也许幸好手头还有备份文件,然而当好不 容易把它恢复时,却发现这一天或一段时间内的数据全部泡汤了,怎么 办?只好重来。其实,在大部份情况下,这些数据还在被损坏的数据库 里。经分析,大多数时候,数据库的损坏是由于真实记录个数和数据库 表头所记载的记录个数不符引起的,只要把数据库中对应的记录数改为 真实记录数,就可以了。
关于FOXPRO数据库的结构,有很多文献都进行了描述,它主要 由文件头,字段信息,和数据区构成。其中记录个数和记录长度在文件 头说明。下面是修复数据库的C源程序,它可带两个参数,第一个参数 是被损坏的数据库名,第二个参数是目标数据库名。运行该程序后,修 复好的数据放在目标数据库中。若只带一个参数时,程序只判断该数据 库是否被损坏。该程序对索引文件没有进行处理,当数据库修复后,可 在FOXPRO下对数据库进行重建索引,命令如下(假设该数据库名叫 D_NM):
SET INDEX TO D_NM.CDX
REINDEX
/* DBFBU.CPP*/
/*修复数据库*/
#include<stdio.h>
#include<process.h>
#include<conio.h>
#include<malloc.h>
typedef struct{
char dbf_id;
char last[3];
long rec_num; //数据记录个数
unsigned offset; //数据区起始位置偏移值
unsigned rec_size; //单个记录长度
char filler[20];
}filehead; //文件头结构
typedef struct {
char field_name[11];
char field_type;
char dummy[4];
union{
unsigned char len;
struct{
char len;
char dec;
}num_size;
}len_info;
char filler[14];
}rec_stru;//描述字段内容的结构
main(int argc,char * argv[]){
char * filename;
long length,record_num,offset;
filehead Fhead;
FILE * fp,*newfp;
void * buff;
int size,mnum,num;
if(argc<2){
printf("Parameters must >one....");
exit(0);
}
filename=argv[1];//源数据库
if((fp=fopen(filename,"rb"))==NULL){
printf("\nCan not open file %s",argv[1]);
exit(0);
}
fread(&Fhead,sizeof(filehead), 1,fp); //读数据库头信息
offset=ftell(fp);
fseek(fp, 0L, SEEK_END);
length = ftell(fp); //数据库文件的真实长度
fseek(fp,offset, SEEK_SET);
if(Fhead.rec_size==0){ exit(0); }
record_num=(long int)((length-Fhead.offset)/Fhead.rec_size);//数据库的真实记录个数
if(record_num!=Fhead.rec_num){/*若真实记录个数和头信息中记录的个数不同,*/
printf("\nThis dbf is distroyed"); /*则表明数据库已损坏*/
if(argc==3){
newfp=fopen(argv[2],"wb");//打开目标文件
if(newfp==NULL){
printf("Can not open file %s",argv[2]);
exit(1);
}
printf("\nPlease wait a minute.....");
size=(Fhead.offset-sizeof(filehead));//数据库字段结构长度
if(Fhead.dbf_id!=0x03){//数据库的标识符
printf("\nNot a FoxPro25 DBF file");
exit(1);
}
Fhead.rec_num=record_num; //写入正确记录数
fwrite(&Fhead,sizeof(filehead),1,newfp); //写入文件头
if((buff=malloc(size))==NULL)
exit(2);
fread(buff,size, 1,fp);
fwrite(buff,size,1,newfp);//拷贝数据库字段结构
free(buff);
mnum=int(65535/Fhead.rec_size); /*分配最大内存,用于存放整数个记录,以减少读盘次数*/
while(1){
if((buff=malloc(Fhead.rec_size*mnum))==NULL){
if(mnum==1)
exit(1);
mnum--;
}
else
break;
}
num=0;
while(num<(int)(record_num/mnum)){ //拷贝记录
fread(buff,Fhead.rec_size*mnum,1,fp);
fwrite(buff,Fhead.rec_size*mnum,1,newfp);
num++;
}
num=0;
free(buff);
buff=malloc(Fhead.rec_size);
while(num<record_num%mnum){ //拷贝余下的记录
fread(buff,Fhead.rec_size,1,fp);
fwrite(buff,Fhead.rec_size,1,newfp);
num++;
}
if(record_num==0)
fputc(0x0d,newfp);
else
fputc(0x1a,newfp);//写入结束标记
fclose(fp);
fclose(newfp);
free(buff);
printf("\nRebuild dbf O.K...");
}
}
else{
printf("\nThis dbf is O.K....");
}
return 0;
}