http://sogotobj.iteye.com/blog/1065023
十幾年前,dBASE、FoxBase和FoxPro數據庫盛極一時,C/C++程序員使用C/C++直接操作DBF數據文件是理所當然的事,下面是我在1994年寫的一個DBFile類代碼。
DBFIle類的頭文件:
#ifndef__DBFIO_HPP
#define__DBFIO_HPP
#include<stdlib.h>
#include<fstream.h>
#include"marray.hpp"
constint
DB_FieNameSize=11;
classDBField//DBF文件的字段類
{
public:
charname[DB_FieNameSize];
chartype;
intoff;
intnul;
unsignedcharwidth;
unsignedchardec;
DBField()
{
memset(this,0,sizeof(DBField));
}
intoperator==(constDBField&);
intoperator<(constDBField&);
DBField&operator=(constDBField&);
//設置字段.參數:名稱,類型,寬度,小數位
voidSetValue(char*,int,int,int=0);
};
inlineintDBField::operator==(constDBField&d)
{
return!strcmp(name,d.name);
}
inlineintDBField::operator<(constDBField&d)
{
returnstrcmp(name,d.name)<0?1:0;
}
inlineDBField&DBField::operator=(constDBField&d)
{
memmove(this,&d,sizeof(DBField));
return*this;
}
//定義排序字段數組類
typedefMSArray<DBField>DBFieldArray;
classDBFile:publicfstream//DBF文件類
{
typedefstruct
{
unsignedchardbfflag;
unsignedchardate_n;
unsignedchardate_y;
unsignedchardate_r;
longrecords;
unsignedldb,lrd;
char_nul[20];
}DBFSTRUCT;
DBFSTRUCTstr;
char*buf;
DBFieldTmpField;
intfields;
longoldrecords;
intopenerror;
DBFieldArraydArray;
voidSetBuf();
voidInit();
voidSetFields(int);
voidWriteDelFlag(long,int='*');
public:
DBFile();
//調用Use(char*)
DBFile(constchar*);
//調用Use(char*,DBField*,int)
DBFile(constchar*,DBField*,int);
~DBFile();
//打開一個已存在文件;參數:文件名
voidUse(constchar*);
//用一字段數組建立新文件;參數:文件名,字段數組,字段數
voidUse(constchar*,DBField*,int);
//關閉文件
voidUse();
voidClose();
//返回記錄數
longRecords();
//返回記錄長度
intRecSize();
//返回文件頭結構長度
intTopSize();
//返回字段數
intFields();
//返回打開文件時的錯誤代碼,錯誤碼:
//0無錯誤
//1文件不存在
//2建立新文件失敗
//3建立文件時未設置字段
//4讀文件頭出錯或非DBF文件
//5寫文件頭出錯
//6內存不夠
intOpenError();
//把當前記錄內容讀到緩衝區
voidRead();
//將緩衝區內容寫到當前記錄
voidWrite();
//取一字段內容到字符串中;參數:字段名,字符串
char*Get(char*,char*);
//取一字段內容到字符串中;參數:字段序號(按字段名排過序),字符串
char*Get(unsigned,char*);
//將字符串內容輸出到字段中;參數:字段名,字符串
voidPut(char*,constchar*);
//將字符串內容輸出到字段中;參數:字段序號(按字段名排過序),字符串
voidPut(unsigned,constchar*);
//將一浮點數輸出到字段中;參數:,字段名,浮點數
voidPut(char*,double);
//將一浮點數輸出到字段中;參數:字段序號(按字段名排過序),浮點數
voidPut(unsigned,double);
//將緩衝區內容追加到文件尾;參數:追加標記(0空記錄)
voidAppend(int=0);
//將一字段內容轉換爲浮點數返回(未檢查字段類型);參數:字段名
doubleoperator[](char*);
//功能同上;參數:字段序號(按字段名排過序)
doubleoperator[](unsigned);
//移動文件記錄put指針;參數:記錄號
voidSeekp(long);
//移動文件記錄get指針;參數:記錄號
voidSeekg(long);
//將緩衝區內容輸出到文件;參數:記錄號
DBFile&operator<<(long);
//從文件中輸入內容到緩衝區中;參數:記錄號
DBFile&operator>>(long);
//返回緩衝區指針
char*Buf();
//在字段排序數組中查找字段,返回序號,未找到返回0X7FFF;參數:字段名
unsignedFindField(char*);
//返回字段排序數組
DBFieldArray&FieldArray();
//給記錄打上刪除標記
voidDelete(long);
//取消記錄的刪除標記
voidUnDelete(long);
//如記錄號在文件記錄範圍內返回TRUE,否則返回FALSE
intInRecords(long);
};
inlineDBFile::DBFile():dArray(0,1)
{
Init();
}
inlinelongDBFile::Records()
{
returnstr.records;
}
inlineintDBFile::RecSize()
{
returnstr.lrd;
}
inlineintDBFile::TopSize()
{
returnstr.ldb;
}
inlineintDBFile::Fields()
{
returnfields;
}
inlinechar*DBFile::Buf()
{
returnbuf;
}
inlineDBFieldArray&DBFile::FieldArray()
{
returndArray;
}
inlinevoidDBFile::Use()
{
Close();
}
inlineDBFile::~DBFile()
{
Close();
}
inlineintDBFile::OpenError()
{
returnopenerror;
}
inlineunsignedDBFile::FindField(char*name)
{
strcpy(TmpField.name,strupr(name));
returndArray.Find(TmpField);
}
inlinevoidDBFile::Read()
{
read(buf,str.lrd);
}
inlinevoidDBFile::Write()
{
*buf=32;
write(buf,str.lrd);
}
inlinechar*DBFile::Get(char*name,char*s)
{
returnGet(FindField(name),s);
}
inlinevoidDBFile::Put(char*name,constchar*s)
{
Put(FindField(name),s);
}
inlinevoidDBFile::Put(char*name,doubles)
{
Put(FindField(name),s);
}
inlinedoubleDBFile::operator[](char*name)
{
returnatof(Get(name,str._nul));
}
inlinedoubleDBFile::operator[](unsignedi)
{
returnatof(Get(i,str._nul));
}
inlinevoidDBFile::Seekp(longrecnum)
{
seekp(recnum*str.lrd+str.ldb);
}
inlinevoidDBFile::Seekg(longrecnum)
{
seekg(recnum*str.lrd+str.ldb);
}
inlinevoidDBFile::Delete(longrecnum)
{
WriteDelFlag(recnum);
}
inlinevoidDBFile::UnDelete(longrecnum)
{
WriteDelFlag(recnum,32);
}
inlineintDBFile::InRecords(longrecnum)
{
return(recnum>=0&&recnum<str.records);
}
#endif
DEFile類的CPP文件:
#include"dbfio.hpp"
#include<ctype.h>
voidDBField::SetValue(char*n,intt,intw,intd)
{
strcpy(name,strupr(n));
type=toupper(t);
width=w;
dec=d;
}
voidDBFile::Init()
{
fields=0;
buf=0;
}
voidDBFile::SetFields(intn)
{
fields=n;
if(n)
{
dArray.SetLimit(n);
buf=newchar[str.lrd+1];
buf[0]=32;
buf[str.lrd]=0x1a;
if(!buf||!dArray.Items())
openerror=6;
}
}
voidDBFile::Close()
{
if(oldrecords!=str.records)
{
seekp(4);
write((char*)&str.records,sizeof(unsignedlong));
oldrecords=str.records;
}
close();
if(buf)
delete[]buf;
dArray.RemoveAll();
Init();
if(openerror)
setstate(ios::badbit);
}
char*DBFile::Get(unsignedi,char*s)
{
if(i<dArray.Count())
{
memcpy(s,&buf[dArray[i].off],dArray[i].width);
s[dArray[i].width]=0;
}
else
*s=0;
returns;
}
DBFile&DBFile::operator>>(longrecnum)
{
if(InRecords(recnum))
{
Seekg(recnum);
Read();
}
else
memset(buf,32,str.lrd);
return*this;
}
voidDBFile::WriteDelFlag(longrecnum,intFlag)
{
Seekp(recnum);
write((char*)&Flag,1);
}
//DBFPUT.CPP
#include"dbfio.hpp"
#include<strstrea.h>
#include<iomanip.h>
#include<bcd.h>
voidDBFile::Put(unsignedi,constchar*s)
{
if(i<dArray.Count())
{
intflag=ios::left;
ostrstreamos(buf,str.lrd);
os.seekp(dArray[i].off);
if(dArray[i].type=='N'||dArray[i].type=='F')
flag=ios::right;
os<<setw(dArray[i].width)<<setiosflags(flag)<<s;
}
}
voidDBFile::Put(unsignedi,doubleval)
{
if(i<dArray.Count())
{
ostrstreamos(buf,str.lrd);
bcda(val,dArray[i].dec);
os.seekp(dArray[i].off);
os<<setw(dArray[i].width)<<setiosflags(ios::right|ios::fixed)<<a;
}
}
voidDBFile::Append(intflag)
{
if(!flag)
memset(buf,32,str.lrd);
Seekp(str.records);
Write();
str.records++;
}
DBFile&DBFile::operator<<(longrecnum)
{
if(InRecords(recnum))
{
Seekp(recnum);
Write();
}
else
Append(1);
return*this;
}
//DBFUSE.CPP
#include"dbfio.hpp"
DBFile::DBFile(constchar*name):dArray(0,1)
{
Init();
Use(name);
}
voidDBFile::Use(constchar*name)
{
if(fields)
Close();
open(name,ios::in|ios::out|ios::binary|ios::nocreate);
if(bad())
{
openerror=1;
return;
}
openerror=0;
read((char*)&str,sizeof(DBFSTRUCT));
oldrecords=str.records;
if(fail()||str.dbfflag!=3)
openerror=4;
else
SetFields(str.ldb/32-1);
if(!openerror)
{
DBFieldField;
for(inti=0;i<fields;i++)
{
read((char*)&Field,sizeof(DBField));
dArray.Add(Field);
seekg(32-sizeof(DBField),ios::cur);
}
seekg(1,ios::cur);
if(fail())
openerror=4;
}
if(openerror)
Close();
}
DBFile::DBFile(constchar*name,DBField*fie,intn):dArray(0,1)
{
Init();
Use(name,fie,n);
}
voidDBFile::Use(constchar*name,DBField*fie,intn)
{
if(!fie||!n)
{
openerror=3;
return;
}
if(fields)
Close();
openerror=0;
str.lrd=1;
for(inti=0;i<n;str.lrd+=fie[i].width,i++)
fie[i].off=str.lrd;
str.dbfflag=3;
str.date_n=96;
str.date_y=str.date_r=1;
str.ldb=n*32+33;
memset(str._nul,0,20);
open(name,ios::in|ios::out|ios::binary|ios::trunc);
if(bad())
openerror=2;
else
{
str.records=oldrecords=0;
write((char*)&str,sizeof(DBFSTRUCT));
SetFields(n);
if(!openerror)
{
for(inti=0;i<fields;i++)
{
write((char*)&fie[i],sizeof(DBField));
write(str._nul,32-sizeof(DBField));
dArray.Add(fie[i]);
}
i=0x0d;
write((char*)&i,1);
if(fail())
openerror=5;
}
}
if(openerror)
Close();
}
#ifndef__MARRAY_HPP
#define__MARRAY_HPP
#include<string.h>
#include<iostream.h>
//無序直接數組類模板.用戶類中應定義默認構造函數和運算符==.
template<classT>classMArray
{
protected:
char*items;//動態數組指針
intcount;//數組中對象個數
intlimit;//數組容量
intdelta;//數組增量
inttypesize;
MArray(){}
voidInit(int,int,int);
virtualT&Item(intindex)
{
return*(T*)&items[index*typesize];
}
virtualvoidLet(intindex,constT*t)
{
memmove(&items[index*typesize],t,typesize);
}
public:
//構造函數.參數:數組容量(個);增加量
MArray(int,int=0);
~MArray();
voidSetLimit(int);
//移去一個對象,其後對象前移.參數:數組下標
voidRemove(int);
//移去指定位置及其後的所有對象;參數:數組下標
voidRemoveAll(int=0);
//增加對象到指定位置,其後對象後移,返回實際下標,出錯返回0x7fff.
//參數:數組下標;對象
intAddAt(int,constT&);
//增加對象到數組尾部,返回實際的數組下標,出錯返回0x7fff.參數:對象
intAdd(constT&);
//返回動態數組指針
char*Items();
//查找對象,返回對象下標,未找到返回0X7FFF.參數:對象
intFind(constT&);
//返回數組中的對象個數
intCount();
//返回數組容量大小
intArraySize();
//返回對象的內存長度
intObjectSize();
//返回數組下標所指的對象,下標超範圍時返回值不定