十几年前,dBASE、FoxBase和FoxPro数据库盛极一时,C/C++程序员使用C/C++直接操作DBF数据文件是理所当然的事,下面是我在1994年写的一个DBFile类代码。
DBFIle类的头文件:
//DBFIO.HPP
#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文件:
//DBFILE.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();
}
DBFIle类所使用的动态数组模板类文件:
//MARRAY.HPP
#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();
//返回数组下标所指的对象,下标超范围时返回值不定
T&operator[](int);
};
template<classT>inlineMArray<T>::MArray(intmLimit,intmDelta)
{
Init(mLimit,mDelta,sizeof(T));
}
template<classT>inlinevoidMArray<T>::RemoveAll(intindex)
{
if(index>=0&&index<count)
count=index;
}
template<classT>inlinechar*MArray<T>::Items()
{
returnitems;
}
template<classT>inlineintMArray<T>::Add(constT&t)
{
returnAddAt(count,t);
}
template<classT>inlineintMArray<T>::Count()
{
returncount;
}
template<classT>inlineintMArray<T>::ArraySize()
{
returnlimit;
}
template<classT>inlineintMArray<T>::ObjectSize()
{
returntypesize;
}
template<classT>inlineT&MArray<T>::operator[](intindex)
{
returnItem(index);
}
#pragmaoption-Jgx
template<classT>
voidMArray<T>::Init(intmLimit,intmDelta,intsize)
{
items=0;
count=0;
limit=0;
delta=mDelta;
typesize=size;
SetLimit(mLimit);
}
template<classT>MArray<T>::~MArray()
{
if(items)
delete[]items;
}
template<classT>voidMArray<T>::SetLimit(intaLimit)
{
if(aLimit<=limit)
return;
if(aLimit>0xfff0/typesize)
aLimit=0xfff0/typesize;
char*aItems=newchar[aLimit*typesize];
if(aItems)
{
if(count)
memmove(aItems,items,count*typesize);
if(items)
delete[]items;
items=aItems;
limit=aLimit;
}
}
template<classT>voidMArray<T>::Remove(intindex)
{
if(index<0||index>=count)
return;
count--;
if(count)
memmove(&items[index*typesize],
&items[(index+1)*typesize],(count-index)*typesize);
}
template<classT>intMArray<T>::AddAt(intindex,constT&t)
{
if(index<0)
return0x7fff;
if(count==limit)
SetLimit(count+delta);
if(count==limit)
return0x7fff;
if(index<count)
memmove(&items[(index+1)*typesize],
&items[index*typesize],
(count-index)*typesize
);
else
index=count;
Let(index,&t);
count++;
returnindex;
}
template<classT>intMArray<T>::Find(constT&t)
{
for(inti=0;i<count;i++)
if(Item(i)==t)
returni;
return0x7fff;
}
#pragmaoption-Jg
//有序直接数组类模板.用户类中应定义默认构造函数和运算符==和<.
template<classT>classMSArray:publicvirtualMArray<T>
{
protected:
intindex;//搜索时保存的数组下标值
intres;//搜索成功标记.0未找到匹配对象
intduplicates;//允许重复插入标记
MSArray(){}
intSearch(constT&key);
public:
//构造函数.参数:数组容量(个);增量;允许重复插入标记(0不允许重复)
MSArray(intl,intd=0,intu=0);
//将对象t按索引方式插到数组中,返回下标.如t属重复对象,
//重复插入标记!=0,t被插入到相同对象的尾部,否则返回0x7fff.
intAdd(constT&t);
//用二分法查找第一个匹配对象,返回数组下标,无匹配对象返回0x7fff.
intFind(constT&t);
//在Find()基础上,查找下一匹配对象,返回数组下标,无匹配对象返回0x7fff.
intFindNext();
//返回使用Find()或FindNext()后>=关键对象的下标值
intIndexNum()
{
returnindex;
}
};
#pragmaoption-Jgx
template<classT>intMSArray<T>::FindNext()
{
if(res&&duplicates&&++index<count
&&Item(index-1)==Item(index))
returnindex;
res=0;
return0x7fff;
}
template<classT>intMSArray<T>::Search(constT&key)
{
intl=0,i;
inth=count-1;
res=0;
while(l<=h)
{
i=(l+h)>>1;
if(Item(i)<key)
l=i+1;
else
{
h=i-1;
if(Item(i)==key)
{
res=1;
if(!duplicates)
l=i;
}
}
}
index=l;
returnres;
}
template<classT>intMSArray<T>::Add(constT&t)
{
inti=Find(t);
if(i==0x7fff)
i=index;
else
{
if(!duplicates)
return0x7fff;
for(i++;Item(i)==t&&i<count;i++);
}
returnAddAt(i,t);
}
template<classT>intMSArray<T>::Find(constT&t)
{
if(Search(t))
returnindex;
return0x7fff;
}
template<classT>MSArray<T>::MSArray(intl,intd,intu):
MArray<T>(l,d),
duplicates(u),
res(0)
{}
#pragmaoption-Jg
//无序间接数组类模板.退出时不删除对象本身,其余同MArray<T>类
template<classT>classIMArray:publicvirtualMArray<T>
{
protected:
IMArray(){}
virtualvoidLet(inti,constT*t)
{
unsignedlongp=(unsignedlong)t;
memmove(&items[i*typesize],&p,typesize);
}
virtualT&Item(inti)
{
return*(T*)(*(long*)&items[i*typesize]);
}
public:
IMArray(intLimit,intDelta=0)
{
Init(Limit,Delta,sizeof(T*));
}
};
//有序间接数组类模板.退出时不删除对象本身.其余同MSArray<T>类
template<classT>classIMSArray:publicMSArray<T>,publicIMArray<T>
{
protected:
IMSArray(){}
public:
IMSArray(intLimit,intDelta=0,intu=0):
IMArray<T>(Limit,Delta)
{
duplicates=u;
res=0;
}
};
#endif
对以上代码作些简单的说明:
1、DBFile类代码使用的Borland C++ 3.1编译器,其它C++编译器可能要作些修改。
2、DBFile中打开和关闭文件使用的是Use函数,没有使用Open、Create这些熟悉的函数名,是按照dBASE命令习惯命名的。
3、DEFile类没有提供DBF文件排序方法,是因为我还有个通用的 B- 树排序类,实际操作中,需要排序时,2个类结合使用的,那个类有个纯虚方法,需要继承才能使用,因为没有找到以前排序类测试代码例子,所以我正在考虑是否把那个排序类贴上来,如果贴上来,还得写一个例子,而我不用C++的时间太长,机器上又没有安装BC3.1,不知能否写好这个例子。
4、DBFile类使用了动态数组,而当时是没有STL的(即使有,我可能也不会使用,因为DOS下的资源相当紧张,而且BC3.1自身也带有数组类,和现在的STL类似,但是我嫌使用它麻烦),所以自己写了个模板类,该模板类在其它C++版本编译必须做编译选项的修改。
声明,文章的代码是1995年前的东西,只能供初学者们借鉴参考。有错误或建议,请来信:maozefa@hotmail.com
更新:今天找了个以前DBFile类的测试代码,更新在此。另外补充说明一点:这个DBFile类用今天的眼光看,是比较简陋的,其中的方法也较低阶,一般数据文件操作方法如First、Last、Next、Bof、Eof等都没有。原因是当时使用C/C++的人,一般都不大喜欢dBASE,但是为了能读取当时大量的dbf文件的数据,写一个能读dbf文件,转换成自己的文件格式的代码就不错了,我这个类在当时已经是很完善了,不仅能读写,还能创建dbf文件。通过以前这个例子,不难看出,我们当时需要的只是文件转换,或者数字字段计算功能(对数字字段使用了[]重载,可以直接以字段名或字段序号操作)[2007-9-17 13:43P]。
#include<iostream.h>
#include"DBFio.hpp"
voidCreateDbf(char*fileName)
{
DBFieldfields[3];
fields[0].SetValue("Code",'C',4);
fields[1].SetValue("Name",'C',8);
fields[2].SetValue("Value",'N',10,2);
DBFileDbf;
Dbf.Use(fileName,fields,3);
Dbf.Put("Code","0001");
Dbf.Put("Name","Maozefa");
Dbf.Put("Value",12345.67);
Dbf.Append(1);
Dbf.Put("Code","0002");
Dbf.Put("Name","Maojun");
Dbf.Put("Value",78543.21);
Dbf.Append(1);
Dbf.Use();
}
voidmain()
{
CreateDbf("Test.dbf");
DBFiledbf("Test.dbf");
charcode[5],name[9];
for(longi=0;i<dbf.Records();i++)
{
dbf.Read();
dbf.Get("Code",code);
dbf.Get("Name",name);
cout<<code<<''<<name<<''<<dbf["Value"]<<endl;
}
system("pause");
}
声明,文章的代码是1995年前的东西,只能供初学者们借鉴参考。有错误或建议,请来信:maozefa@hotmail.com
分享到:
相关推荐
sjshq.dbf-------用于测试服务器端原代码----股票实时行情---------深圳dbf
功能:操作DBF文件的C++代码,可以创建DBF文件、读取DBF文件、写入DBF文件、拷贝DBF文件的结构 环境:需要C++11和BOOST库,需要设置环境变量BOOST_HOME指向BOOST的根目录 例子:见main.cpp
dbf-jdbc-wisecoders,JAVA 读写DBF文件工具包
深入剖析dbf文件,以文件形式读取dbf文件. 不需要安装Visual Foxpro驱动,非常值得学习
200805月,最近写了一个操作dbf文件的c++类,可以读、追加、删除、搜索,我觉得代码写得比较清晰,对函数写了中文注释。但是功能还不强大,只支持char类型的字段,不能创建新dbf文件。希望对大家有帮助,也希望大家...
c++ DBF 读取数据库DBF格式,实例代码 c++ DBF 读取数据库DBF格式,实例代码
操纵DBF数据库文件的C++类及库,老外的东西。
DBF读写文件 C++ 查找 一次查找一个 一次查找多个 附带测试文件
DBF解压程序.适合大多数DBF数据文件
arcgis10.2以后,shp文件属性表中文会有乱码的情况(该情况通常在原有低版本arcgis升级版本后才出现),解决属性表乱码的插件
Kettle8.0清洗交易所DBF文件数据 Kettle8.0清洗交易所DBF文件数据 Kettle8.0清洗交易所DBF文件数据
行业分类-设备装置-DBF数据导出平台及其导出方法.zip
Java library for fast reading/writing DBF-files. Build from sources For build project from sources you need to run gradlew script from the root directory: git clone git@github.com:jamel/dbf.git cd dbf...
一个用来操作DBF的类,非常好用,找了好久才找到,希望能帮助你
show2003.dbf----用于测试服务器端源代码-------2017年之前股票实时行情交易所格式
ArcGIS默认dbf代码页-设置为UTF-8,解决有需要将gdb导出成shape file并将字符集设置成Utf-8以避免中文乱码的情况。
VC操作DBF数据库文件的类,用于读写dbf文件
精彩编程与编程技巧-DBF文件转为MDB文件的方法 ...
使用Day2Dbf工具指定行情软件所在地址,自动导出历史数据到dbf文件。
就是武汉大学的一个考试的题目,要求用C++写dbf3