几个月前,翻出以前的一些1993 - 1995年的C/C++老代码,陆续粘贴到了BLOG上,一来以免不小心遗失(以前很多好代码都丢了),二来可供C/C++爱好者,特别是初学者借鉴参考,本以为就这些了,没料到月头又找出一些更老的代码,都是1991年及以前的。
几个月前,翻出以前的一些1993 - 1995年的C/C++老代码,陆续粘贴到了BLOG上,一来以免不小心遗失(以前很多好代码都丢了),二来可供C/C++爱好者,特别是初学者借鉴参考,本以为就这些了,没料到月头又找出一些更老的代码,都是1991年及以前的,前几天我发上来的《
C语言版的磁盘文件分片归并排序函数》就是其中之一。今天准备把1991年用TURBOC 2.0写的DBF本地数据库文件操作函数完整的贴在这里,前几个月发的文章《
C++老代码 -- DBF数据文件操作类DBFile》应该是我当时从C向C++过渡时根据这里的C代码改写的。
其实还有个通用的用B+树建立本地数据索引文件的工具代码,本想在《C语言版的磁盘文件分片归并排序函数》之后贴上来,但是由于目前32位计算机与以前的16位计算机的数据类型长度不一样,而索引文件是分索引节点块写道磁盘文件上的,数据类型长度不同必定引起移植错误(以前没想这么多 ^_^ ),再看到《C语言版的磁盘文件分片归并排序函数》很受朋友们捧场(一天的电击量达到了1000多),错误多了会挨骂的,所以,只能等春节后找几天时间改一下(代码很长很复杂的)后再贴出来。顺便在此感谢大家的捧场,也感谢CSDN编辑把文章挂在了首页,才能让这么多的朋友光临。
需要说明的是,1991年我正好业余学习计算机语言2年多时间,其中包括学习BASIC、PASCAL及汇编等,所以C语言可能掌握的不大好,更谈不上代码设计,加上我又不懂英语,标识符命名也不规范等,因此有什么不对的地方可以写信给我(maozefa@hotmail.com),也可留言,但是代码在16位机上绝对是可行的,记得我以前经常用的,但是要用到32位机上,和DBF文件有关的几个结构的数据类型要改一下,很简单的,只是把int变为short就行了的(好像就2处地方),我自己没改是因为该代码与2个通用排序函数不一样,目前实用价值不大,就让它保持原样吧!
下面是代码,没写测试程序:
/*
********************* DBASE 数据文件操作 C 库文件 ************************
* 文 件 名 : MDBFIO.H *
* 编 制 人 : 湖北省公安县统计局 毛 泽 发 *
* 日 期 : 1991.8 *
***************************************************************************
*/
#include <stdio.h>
#define MAXFILES 10
#define MAXFIELD 128 /* ... ... 记录最大字段数 */
#define MAXNAMES 11 /* ... ... 字段名最大长度 */
#define MAXFIESIZE 254 /* ... ... 字符字段最大位数 */
#define MAXWIDTH 19 /* ... ... 数据字段最大位数 */
#define MAXDEC 15 /* ... ... 数据小数最大位数 */
#define DBFFILE 3 /* ... ... 头结构开始标记 */
#define DBFSTREND 0x000d /* ... ... 头结构结束标记 */
#define DBFEND 26 /* ... ... 文件结束标记 */
#define DELFLAG '*' /* 记录删除标记 */
#define TOP 0l /* 首记录标志 */
#define BOTTOM -1 /* 末记录标志 */
#define SPACE 32
/* 内部字段信息结构 */
typedef struct dbfield{
char name[MAXNAMES]; /* 字段名 */
char type; /* 字段类型 */
void far *tech; /* 字段数据地址 */
unsigned char width, dec; /* 字段长度及小数位 */
char nul[14]; /* 保留字节 */
}DBFIELD;
/* DBF 文件头结构 */
typedef struct dbfstr {
unsigned char dbf3; /* DBASE 数据文件标记 */
unsigned char date_n,date_y,date_r; /* 年月日变量 */
unsigned long record; /* 记录数变量 */
unsigned int ldb,lrd; /* 头结构.记录长度变量 */
char nul[20]; /* 头结构保留字节变量 */
}DBFSTR;
/* DBF 文件把柄结构 */
typedef struct dbfile {
FILE *fdb; /* 文件指针 */
DBFSTR stru; /* 文件头结构 */
DBFIELD *start; /* 字段结构首指针 */
char fields; /* 字段数 */
}DBFILE;
/* 外部字段信息结构 */
struct dbf{
char name[MAXNAMES]; /* 字段名变量 */
char type; /* 字段类型变量 */
unsigned char width,dec; /* 字段长度及小数位变量 */
};
/* db_error DBASE 文件操作出错信息:
0: 无错误; 1: 打开文件过多; 2: 文件未找到; 3: 读文件头失败; 4: 写文件头失败;
5: 关闭文件失败; 6: 打开文件失败; 7: 移动文件指针出错.
*/
extern unsigned char db_error;
int db_getfields(DBFSTR str); /* 计算并返回文件字段数 */
void undberror(void); /* 清除 DB_ERROR 错误信息 */
int db_getstr(DBFILE *f); /* 读文件头信息, 成功返回 1,否则 0 */
DBFILE *db_use(char *fname); /* 打开一个已存在文件,返回指针供读写, 出错返回 NULL */
/* 根据外部字段结构创建一个 .DBF 文件,成功返回指针供读写,出错返回 NULL */
DBFILE *db_create(char *fname, struct dbf *fd);
/* 关闭一个文件,FLAG = 0,不更新文件头,否则更新;成功返回 1,否则 0 */
int db_close(DBFILE *f, int flag);
/* 写文件头信息,FLAG = 0 不写字段信息,成功返回 1,否则 0 */
int db_writestr(DBFILE *f, int flag);
long db_cpyrec(DBFILE *fo, DBFILE *fi, long fosta, long fista, long n,int *fields);
long db_fappend(DBFILE *fo, DBFILE *fi, long starec, long n, int *fields);
int db_copy(char *tofname, char *ffname, int flag, long starec, long n,int *fields);
long db_goto(DBFILE *f, long record);
long db_getrecnum(DBFILE *f);
long db_skip(DBFILE *f, long n);
int db_delete(DBFILE *f, long recs);
int db_recall(DBFILE *f, long recs);
int db_pack(char *fname);
/*** DBFIO.H END ***/
/*
********************* DBASE 数据文件操作 C 库文件 ************************
* 文 件 名 : DB_CLOSE.C *
* 编制人日期 : 湖北省公安县统计局 毛 泽 发 (1991.8) *
***************************************************************************
*/
#include <dos.h>
#include <stdlib.h>
#include "dbfio.h"
#ifdef TURBOC
#include <alloc.h>
#else
#include <malloc.h>
#endif
/*
********************* DBASE 数据文件操作 C 库函数 ***********************
* 函 数 名: DB_DATE *
* 参 数: DAT 数据文件头结构指针 *
* 功 能: 读系统当前时间到头结构中 *
* 返 回 值: *
***************************************************************************
*/
void db_date(DBFSTR *dat)
{
char *p, q[5];
union REGS inr;
inr.h.ah = 0x2a;
intdos(&inr, &inr);
p = itoa(inr.x.cx, q, 10) + 2;
dat->date_n = atoi(p);
dat->date_y = inr.h.dh;
dat->date_r = inr.h.dl;
}
/*
********************* DBASE 数据文件操作 C 库函数 ***********************
* 函 数 名: DB_CLOSE *
* 参 数: f DBASE 数据文件指针 *
* 功 能: 关闭一个 DBASE 数据文件 *
* 返 回 值: 成功 1,否则 0 *
***************************************************************************
*/
int db_close(DBFILE *f, int flag)
{
if(!f->fdb) return 0; /* 无效文件号 */
if(flag){ /* 如已向文件写数据,更新文件头结构 */
db_date(&f->stru);
if(!db_writestr(f, 0)) return 0;
}
if(fclose(f->fdb) == EOF){
db_error = 5;
return 0;
}
free(f->start);
f->fdb = NULL;
return 1;
}
/*
********************* DBASE 数据文件操作 C 库函数 ***********************
* 函 数 名: db_writestr *
* 参 数: f:DBASE 数据文件指针,flag = 0不写字段信息,否则整个文件头信息 *
* 功 能: 写文件头信息到数据文件 *
* 返 回 值: 成功 1,否则 0 *
***************************************************************************
*/
int db_writestr(DBFILE *f, int flag)
{
int dbend = DBFSTREND;
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, sizeof(int), 1, f->fdb)) goto err;
}
return 1;
err:
db_error = 4;
}
/*** DB_CLOSE.C END ***/
/*
********************* DBASE 数据文件操作 C 库文件 ************************
* 文 件 名 : DB_COPY.C *
* 编制人日期 : 湖北省公安县统计局 毛 泽 发 (1991.8) *
***************************************************************************
*/
#include "dbfio.h"
#ifdef TURBOC
#include <alloc.h>
#else
#include <malloc.h>
#endif
#include <string.h>
/*
********************* DBASE 数据文件操作 C 库函数 ***********************
* 函 数 名: DB_COPY *
* 参 数: tofname:复制文件名;ffname:被复制文件名;flag:0 只复制结构,1 包*
* 括记录;starec:起始记录(0-N); n:记录数;如 n = 0,start及以下全 *
* 部记录;fileds:字段序号表,以 -1 结尾,如fields = 0 复制全部字段*
* 功 能: 按条件复制一个文件内容到另一文件中 *
* 返 回 值: 成功 0,被复制文件不存在 -1, 复制失败 -2 *
***************************************************************************
*/
int db_copy(char *tofname, char *ffname, int flag, long starec, long n,
int *fields)
{
DBFILE *fi, *fo, *db_findfile();
register int i = 0, j;
if((fo = db_findfile()) == NULL) return -2;
if((fo->fdb = fopen(tofname, "w+b")) == NULL){
db_error = 6;
return -2;
}
if((fi = db_use(ffname)) == NULL) return -1;
memcpy((char *)&fo->stru, (char *)&fi->stru, sizeof(DBFSTR));
if(!fields){
fo->start = fi->start;
fo->fields = fi->fields;
}
else{
for(; fields[i] >= 0 && fields[i] < fi->fields && i < MAXFIELD; i ++);
j = sizeof(DBFIELD) * i;
if((fo->start = (DBFIELD *)malloc(j)) == NULL){
db_close(fi, 0);
fclose(fo->fdb);
fo->fdb = NULL;
return -2;
}
memset(fo->start, 0, j);
fo->fields = i;
fo->stru.lrd = 0;
for(i = 0; i < fo->fields; i ++){
j = fields[i];
memcpy((char *)&fo->start[i], (char *)&fi->start[j], sizeof(DBFIELD));
fo->stru.lrd += fo->start[i].width;
}
fo->stru.lrd += 1;
fo->stru.ldb = i * 32 + 34;
}
if(flag) db_cpyrec(fo, fi, 0l, starec, n, fields);
db_close(fi, 0);
i = db_writestr(fo, 1);
if(fields) free(fo->start);
fclose(fo->fdb);
fo->fdb = NULL;
if(!i){
remove(tofname);
return -2;
}
}
/*** DB_COPY.C END ***/
/*
********************* DBASE 数据文件操作 C 库文件 ************************
* 文 件 名 : DB_CPYRE.C *
* 编制人日期 : 湖北省公安县统计局 毛 泽 发 (1991.8) *
***************************************************************************
*/
#include "dbfio.h"
#ifdef TURBOC
#include <alloc.h>
#else
#include <malloc.h>
#endif
/*
********************* DBASE 数据文件操作 C 库函数 ***********************
* 函 数 名: DB_CPYREC *
* 参 数: fo,fi:分别为复制.被复制文件指针;fosta,fista:分别为fo,fi所指文*
* 件起始记录;n:记录数,n = 0,包括 fista 在内以下全部记录;fields;*
* 字段序号表,为 NULL 复制全部字段 *
* 功 能: 复制 fi 文件的记录到 fo 文件,如 fo 与 fi 或者 fields 字段数. *
* 对应字段类型.长度及小数不匹配,数据库会出错 *
* 返 回 值: fo 文件实际记录数(注:必须调用 DB_CLOSE 关库后,文件记录才更新)*
***************************************************************************
*/
long db_cpyrec(DBFILE *fo, DBFILE *fi, long fosta, long fista, long n,
int *fields)
{
register unsigned long i;
unsigned long p, q;
register int j, k;
char *buf;
if((buf = (char *)malloc(fi->stru.lrd)) == NULL) return 0l;
if(db_goto(fo, fosta) == -1l || db_goto(fi, fista) == -1l) return 0l;
if(!n) n = fi->stru.record - fista;
if(!fields){
for(i = 0l; i < n; i ++){
if(!fread(buf, fi->stru.lrd, 1, fi->fdb)) break;
if(*buf == DELFLAG){
i --; n --;
continue;
}
if(!fwrite(buf, fo->stru.lrd, 1, fo->fdb)) break;
}
}
else{
char *s, *p;
int m, h;
if((s = (char *)malloc(fo->stru.lrd)) == NULL) return 0l;
for(i = 0l; i < n; i ++){
p = s;
if(!fread(buf, fi->stru.lrd, 1, fi->fdb)) break;
if(*buf == DELFLAG){
i --; n --;
continue;
}
*p ++ = *buf;
for(m = 0; fields[m] >= 0; m ++){
for(k = 0, j = 1; k < fields[m]; j += fi->start[k].width, k ++);
for(h = k, k = j, j += fi->start[h].width; k < j; k ++) *p ++ = buf[k];
}
if(!fwrite(s, fo->stru.lrd, 1, fo->fdb)) break;
}
free(s);
}
free(buf);
fo->stru.record = fosta + i;
return fo->stru.record;
}
/*
********************* DBASE 数据文件操作 C 库函数 ***********************
* 函 数 名: DB_FAPPEND *
* 参 数: starec:为被追加文件起始记录.其余参数 同 DB_CPYREC. *
* 功 能: 追加 fi 文件的记录到 fo 文件尾部,其它同 DB_CPYREC *
* 返 回 值: fo 文件实际记录数,其它同 DB_CPYREC *
***************************************************************************
*/
long db_fappend(DBFILE *fo, DBFILE *fi, long starec, long n, int *fields)
{
return(db_cpyrec(fo, fi, fo->stru.record, starec, n, fields));
}
/*** DB_CPYRE.C END ***/
/*
********************* DBASE 数据文件操作 C 库文件 ************************
* 文 件 名 : DB_CREAT.C *
* 编制人日期 : 湖北省公安县统计局 毛 泽 发 (1991.8) *
***************************************************************************
*/
#include "dbfio.h"
#ifdef TURBOC
#include <alloc.h>
#else
#include <malloc.h>
#endif
#include <string.h>
/*
********************* DBASE 数据文件操作 C 库函数 ***********************
* 函 数 名: DB_VERIFIELD *
* 参 数: fd:外部字段结构数组首指针,末尾字段名首字符应为 "" *
* 功 能: 检验并校正字段类型.长度和小数位 *
* 返 回 值: 字段数 *
***************************************************************************
*/
int db_verifield(struct dbf *fd)
{
register int i, j;
for(i = 0; fd[i].name[0] && i < MAXFIELD; i ++){
if(fd[i].type > 'b' && fd[i].type < 'o') fd[i].type -= 32;
if(fd[i].type != 'N') fd[i].dec = 0;
if(fd[i].width == 0) fd[i].width = 1;
switch(fd[i].type){
case 'C':
if(fd[i].width > MAXFIESIZE) fd[i].width = MAXFIESIZE;
break;
case 'N':
if(fd[i].dec > MAXDEC) fd[i].dec = MAXDEC;
if(fd[i].width > MAXWIDTH) fd[i].dec = MAXWIDTH;
if((fd[i].width - fd[i].dec) < 2) fd[i].width = fd[i].dec + 2;
break;
case 'L':
fd[i].width = 1; break;
case 'D':
fd[i].width = 8; break;
case 'M':
fd[i].width = 10; break;
default:
if(fd[i].name[0]){
fd[i].type = 'C'; i -= 2;
}
}
}
return i;
}
/*
********************* DBASE 数据文件操作 C 库函数 ***********************
* 函 数 名: db_create *
* 参 数: fname:文件名; fd:同上 *
* 功 能: 以写/读方式创建一个 DBASE 数据文件 *
* 返 回 值: 成功 DBFILE 指针, 出错 NULL *
***************************************************************************
*/
DBFILE *db_create(char *fname, struct dbf *fd)
{
DBFILE *f, *db_findfile();
register int n, i = 0;
if((f = db_findfile()) == NULL) return NULL;
if((f->fields = db_verifield(fd)) == NULL) 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(n = 0; i < f->fields; i ++){
strcpy(f->start[i].name, fd[i].name);
f->start[i].type = fd[i].type;
f->start[i].width = fd[i].width;
f->start[i].dec = fd[i].dec;
n += fd[i].width;
}
/* 初始化文件头结构 */
f->stru.dbf3 = DBFFILE;
f->stru.record = 0l;
f->stru.ldb = f->fields * 32 + 34;
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;
}
/*** DB_CREAT.C END ***/
/*
********************* DBASE 数据文件操作 C 库文件 ************************
* 文 件 名 : DB_DEL.C *
* 编制人日期 : 湖北省公安县统计局 毛 泽 发 (1991.8) *
***************************************************************************
*/
#include "dbfio.h"
/*
********************* DBASE 数据文件操作 C 库函数 ***********************
* 函 数 名: DB_DELETE *
* 参 数: f:DBASE 数据文件指针;recs:记录号 *
* 功 能: 给记录打上删除标记 *
* 返 回 值: 成功 DELFLAG, 出错 EOF *
***************************************************************************
*/
int db_delete(DBFILE *f, long recs)
{
if(db_goto(f, recs) == -1) return EOF;
return(fputc(DELFLAG, f->fdb));
}
/*
********************* DBASE 数据文件操作 C 库函数 ***********************
* 函 数 名: DB_RECALL *
* 参 数: 同 DB_DELETE *
* 功 能: 恢复打上删除标记的记录 *
* 返 回 值: 成功 SPACE, 出错 EOF *
***************************************************************************
*/
int db_recall(DBFILE *f, long recs)
{
if(db_goto(f, recs) == -1) return EOF;
return(fputc(32, f->fdb));
}
/*
********************* DBASE 数据文件操作 C 库函数 ***********************
* 函 数 名: DB_PACK *
* 参 数: fname:DBASE 数据文件名 *
* 功 能: 重新组合数据库,以去掉带删除标记的记录 *
* 返 回 值: 成功 0 ,出错非零 *
***************************************************************************
*/
int db_pack(char *fname)
{
if(db_copy("$$$$$$$$.$$$", fname, 1, 0l, 0l, NULL)) return -1;
if(remove(fname) == -1) return -1;
return(rename("$$$$$$$$.$$$", fname));
}
/*** DB_DEL.C END ***/
/*
********************* DBASE 数据文件操作 C 库文件 ************************
* 文 件 名 : DB_SEEK.C *
* 编制人日期 : 湖北省公安县统计局 毛 泽 发 (1991.8) *
***************************************************************************
*/
#include "dbfio.h"
/*
********************* DBASE 数据文件操作 C 库函数 ***********************
* 函 数 名: DB_GOTO *
* 参 数: f: DBASE 文件指针;record:记录号 = TOP 首记录, = BOTTOM 末记录*
* 功 能: 移动文件指针到指定的记录号 *
* 返 回 值: 成功:指针在文件的实际位置(字节数),出错 -1 *
***************************************************************************
*/
long db_goto(DBFILE *f, long record)
{
if(record == BOTTOM) record = f->stru.record - 1;
if(record < 0 || record > f->stru.record) record = f->stru.record;
record = record * f->stru.lrd + f->stru.ldb;
if(fseek(f->fdb, record, 0)){
db_error = 7;
return -1l;
}
return record;
}
/*
********************* DBASE 数据文件操作 C 库函数 ***********************
* 函 数 名: DB_GETRECNUM *
* 参 数: f: DBASE 文件指针 *
* 功 能: 返回当前文件指针所在位置的记录号(注:指针不一定指在记录首字节)*
* 返 回 值: 记录号,出错 -n *
***************************************************************************
*/
long db_getrecnum(DBFILE *f)
{
long record;
if((record = ftell(f->fdb)) == -1l){
db_error = 7;
return -1l;
}
record = (record - f->stru.ldb) / f->stru.lrd;
return record;
}
/*
********************* DBASE 数据文件操作 C 库函数 ***********************
* 函 数 名: DB_SKIP *
* 参 数: f: DBASE 文件指针; n:记录数 *
* 功 能: 文件指针从当前记录处移动 N 个记录位置 *
* 返 回 值: 同 DB_GOTO *
***************************************************************************
*/
long db_skip(DBFILE *f, long n)
{
long record;
if((record = db_getrecnum(f)) == -1l) return -1l;
return(db_goto(f, record + n));
}
/*** DB_SEEK.C END ***/
/*
********************* DBASE 数据文件操作 C 库文件 ************************
* 文 件 名 : DB_USE.C *
* 编制人日期 : 湖北省公安县统计局 毛 泽 发 (1991.8) *
***************************************************************************
*/
#include "dbfio.h"
#ifdef TURBOC
#include <alloc.h>
#else
#include <malloc.h>
#endif
/*
********************* DBASE 数据文件操作 C 库函数 ***********************
* 函 数 名: db_getstr *
* 参 数: f 数据文件指针 *
* 功 能: 读数据文件头信息 *
* 返 回 值: 成功 1,否则 0 *
***************************************************************************
*/
int db_getstr(DBFILE *f)
{
/* 读文件头结构 */
if(!fread(&f->stru, sizeof(DBFSTR), 1, f->fdb) || f->stru.dbf3 != DBFFILE)
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;
}
/*
********************* DBASE 数据文件操作 C 库函数 ***********************
* 函 数 名: DB_USE *
* 参 数: 以读/写方式打开一个已存在的数据文件 *
* 功 能: fname 数据文件名 *
* 返 回 值: 成功 DBFILE 文件指针, 出错 NULL *
***************************************************************************
*/
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; /* 返回文件指针 */
}
/*** DB_USE.C END ***/
Ok,欢迎大家光临!
原文链接:http://blog.csdn.net/maozefa/archive/2008/01/11/2034688.aspx