http://sogotobj.iteye.com/blog/1065023
十几年前,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 "
const int
DB_FieNameSize = 11 ;
class DBField // DBF文件的字段类
{
public :
char name[DB_FieNameSize];
char type;
int off;
int nul;
unsigned char width;
unsigned char dec;
DBField()
{
memset( this , 0 , sizeof (DBField));
}
int operator == ( const DBField & );
int operator < ( const DBField & );
DBField & operator = ( const DBField & );
// 设置字段.参数:名称,类型,宽度,小数位
void SetValue( char * , int , int , int = 0 );
};
inline int DBField:: operator == ( const DBField & d)
{
return ! strcmp(name,d.name);
}
inline int DBField:: operator < ( const DBField & d)
{
return strcmp(name,d.name) < 0 ? 1 : 0 ;
}
inlineDBField & DBField:: operator = ( const DBField & d)
{
memmove( this , & d, sizeof (DBField));
return * this ;
}
// 定义排序字段数组类
typedefMSArray < DBField > DBFieldArray;
class DBFile: public fstream // DBF文件类
{
typedef struct
{
unsigned char dbfflag;
unsigned char date_n;
unsigned char date_y;
unsigned char date_r;
long records;
unsignedldb,lrd;
char _nul[ 20 ];
}DBFSTRUCT;
DBFSTRUCTstr;
char * buf;
DBFieldTmpField;
int fields;
long oldrecords;
int openerror;
DBFieldArraydArray;
void SetBuf();
void Init();
void SetFields( int );
void WriteDelFlag( long , int = ' * ' );
public :
DBFile();
// 调用Use(char*)
DBFile( const char * );
// 调用Use(char*,DBField*,int)
DBFile( const char * ,DBField * , int );
~ DBFile();
// 打开一个已存在文件;参数:文件名
void Use( const char * );
// 用一字段数组建立新文件;参数:文件名,字段数组,字段数
void Use( const char * ,DBField * , int );
// 关闭文件
void Use();
void Close();
// 返回记录数
long Records();
// 返回记录长度
int RecSize();
// 返回文件头结构长度
int TopSize();
// 返回字段数
int Fields();
// 返回打开文件时的错误代码,错误码:
// 0无错误
// 1文件不存在
// 2建立新文件失败
// 3建立文件时未设置字段
// 4读文件头出错或非DBF文件
// 5写文件头出错
// 6内存不够
int OpenError();
// 把当前记录内容读到缓冲区
void Read();
// 将缓冲区内容写到当前记录
void Write();
// 取一字段内容到字符串中;参数:字段名,字符串
char * Get( char * , char * );
// 取一字段内容到字符串中;参数:字段序号(按字段名排过序),字符串
char * Get(unsigned, char * );
// 将字符串内容输出到字段中;参数:字段名,字符串
void Put( char * , const char * );
// 将字符串内容输出到字段中;参数:字段序号(按字段名排过序),字符串
void Put(unsigned, const char * );
// 将一浮点数输出到字段中;参数:,字段名,浮点数
void Put( char * , double );
// 将一浮点数输出到字段中;参数:字段序号(按字段名排过序),浮点数
void Put(unsigned, double );
// 将缓冲区内容追加到文件尾;参数:追加标记(0空记录)
void Append( int = 0 );
// 将一字段内容转换为浮点数返回(未检查字段类型);参数:字段名
double operator []( char * );
// 功能同上;参数:字段序号(按字段名排过序)
double operator [](unsigned);
// 移动文件记录put指针;参数:记录号
void Seekp( long );
// 移动文件记录get指针;参数:记录号
void Seekg( long );
// 将缓冲区内容输出到文件;参数:记录号
DBFile & operator << ( long );
// 从文件中输入内容到缓冲区中;参数:记录号
DBFile & operator >> ( long );
// 返回缓冲区指针
char * Buf();
// 在字段排序数组中查找字段,返回序号,未找到返回0X7FFF;参数:字段名
unsignedFindField( char * );
// 返回字段排序数组
DBFieldArray & FieldArray();
// 给记录打上删除标记
void Delete( long );
// 取消记录的删除标记
void UnDelete( long );
// 如记录号在文件记录范围内返回TRUE,否则返回FALSE
int InRecords( long );
};
inlineDBFile::DBFile():dArray( 0 , 1 )
{
Init();
}
inline long DBFile::Records()
{
return str.records;
}
inline int DBFile::RecSize()
{
return str.lrd;
}
inline int DBFile::TopSize()
{
return str.ldb;
}
inline int DBFile::Fields()
{
return fields;
}
inline char * DBFile::Buf()
{
return buf;
}
inlineDBFieldArray & DBFile::FieldArray()
{
return dArray;
}
inline void DBFile::Use()
{
Close();
}
inlineDBFile:: ~ DBFile()
{
Close();
}
inline int DBFile::OpenError()
{
return openerror;
}
inlineunsignedDBFile::FindField( char * name)
{
strcpy(TmpField.name,strupr(name));
return dArray.Find(TmpField);
}
inline void DBFile::Read()
{
read(buf,str.lrd);
}
inline void DBFile::Write()
{
* buf = 32 ;
write(buf,str.lrd);
}
inline char * DBFile::Get( char * name, char * s)
{
return Get(FindField(name),s);
}
inline void DBFile::Put( char * name, const char * s)
{
Put(FindField(name),s);
}
inline void DBFile::Put( char * name, double s)
{
Put(FindField(name),s);
}
inline double DBFile:: operator []( char * name)
{
return atof(Get(name,str._nul));
}
inline double DBFile:: operator [](unsignedi)
{
return atof(Get(i,str._nul));
}
inline void DBFile::Seekp( long recnum)
{
seekp(recnum * str.lrd + str.ldb);
}
inline void DBFile::Seekg( long recnum)
{
seekg(recnum * str.lrd + str.ldb);
}
inline void DBFile::Delete( long recnum)
{
WriteDelFlag(recnum);
}
inline void DBFile::UnDelete( long recnum)
{
WriteDelFlag(recnum, 32 );
}
inline int DBFile::InRecords( long recnum)
{
return (recnum >= 0 && recnum < str.records);
}
#endif
#ifndef__DBFIO_HPP
#define __DBFIO_HPP
#include < stdlib.h >
#include < fstream.h >
#include " marray.hpp "
const int
DB_FieNameSize = 11 ;
class DBField // DBF文件的字段类
{
public :
char name[DB_FieNameSize];
char type;
int off;
int nul;
unsigned char width;
unsigned char dec;
DBField()
{
memset( this , 0 , sizeof (DBField));
}
int operator == ( const DBField & );
int operator < ( const DBField & );
DBField & operator = ( const DBField & );
// 设置字段.参数:名称,类型,宽度,小数位
void SetValue( char * , int , int , int = 0 );
};
inline int DBField:: operator == ( const DBField & d)
{
return ! strcmp(name,d.name);
}
inline int DBField:: operator < ( const DBField & d)
{
return strcmp(name,d.name) < 0 ? 1 : 0 ;
}
inlineDBField & DBField:: operator = ( const DBField & d)
{
memmove( this , & d, sizeof (DBField));
return * this ;
}
// 定义排序字段数组类
typedefMSArray < DBField > DBFieldArray;
class DBFile: public fstream // DBF文件类
{
typedef struct
{
unsigned char dbfflag;
unsigned char date_n;
unsigned char date_y;
unsigned char date_r;
long records;
unsignedldb,lrd;
char _nul[ 20 ];
}DBFSTRUCT;
DBFSTRUCTstr;
char * buf;
DBFieldTmpField;
int fields;
long oldrecords;
int openerror;
DBFieldArraydArray;
void SetBuf();
void Init();
void SetFields( int );
void WriteDelFlag( long , int = ' * ' );
public :
DBFile();
// 调用Use(char*)
DBFile( const char * );
// 调用Use(char*,DBField*,int)
DBFile( const char * ,DBField * , int );
~ DBFile();
// 打开一个已存在文件;参数:文件名
void Use( const char * );
// 用一字段数组建立新文件;参数:文件名,字段数组,字段数
void Use( const char * ,DBField * , int );
// 关闭文件
void Use();
void Close();
// 返回记录数
long Records();
// 返回记录长度
int RecSize();
// 返回文件头结构长度
int TopSize();
// 返回字段数
int Fields();
// 返回打开文件时的错误代码,错误码:
// 0无错误
// 1文件不存在
// 2建立新文件失败
// 3建立文件时未设置字段
// 4读文件头出错或非DBF文件
// 5写文件头出错
// 6内存不够
int OpenError();
// 把当前记录内容读到缓冲区
void Read();
// 将缓冲区内容写到当前记录
void Write();
// 取一字段内容到字符串中;参数:字段名,字符串
char * Get( char * , char * );
// 取一字段内容到字符串中;参数:字段序号(按字段名排过序),字符串
char * Get(unsigned, char * );
// 将字符串内容输出到字段中;参数:字段名,字符串
void Put( char * , const char * );
// 将字符串内容输出到字段中;参数:字段序号(按字段名排过序),字符串
void Put(unsigned, const char * );
// 将一浮点数输出到字段中;参数:,字段名,浮点数
void Put( char * , double );
// 将一浮点数输出到字段中;参数:字段序号(按字段名排过序),浮点数
void Put(unsigned, double );
// 将缓冲区内容追加到文件尾;参数:追加标记(0空记录)
void Append( int = 0 );
// 将一字段内容转换为浮点数返回(未检查字段类型);参数:字段名
double operator []( char * );
// 功能同上;参数:字段序号(按字段名排过序)
double operator [](unsigned);
// 移动文件记录put指针;参数:记录号
void Seekp( long );
// 移动文件记录get指针;参数:记录号
void Seekg( long );
// 将缓冲区内容输出到文件;参数:记录号
DBFile & operator << ( long );
// 从文件中输入内容到缓冲区中;参数:记录号
DBFile & operator >> ( long );
// 返回缓冲区指针
char * Buf();
// 在字段排序数组中查找字段,返回序号,未找到返回0X7FFF;参数:字段名
unsignedFindField( char * );
// 返回字段排序数组
DBFieldArray & FieldArray();
// 给记录打上删除标记
void Delete( long );
// 取消记录的删除标记
void UnDelete( long );
// 如记录号在文件记录范围内返回TRUE,否则返回FALSE
int InRecords( long );
};
inlineDBFile::DBFile():dArray( 0 , 1 )
{
Init();
}
inline long DBFile::Records()
{
return str.records;
}
inline int DBFile::RecSize()
{
return str.lrd;
}
inline int DBFile::TopSize()
{
return str.ldb;
}
inline int DBFile::Fields()
{
return fields;
}
inline char * DBFile::Buf()
{
return buf;
}
inlineDBFieldArray & DBFile::FieldArray()
{
return dArray;
}
inline void DBFile::Use()
{
Close();
}
inlineDBFile:: ~ DBFile()
{
Close();
}
inline int DBFile::OpenError()
{
return openerror;
}
inlineunsignedDBFile::FindField( char * name)
{
strcpy(TmpField.name,strupr(name));
return dArray.Find(TmpField);
}
inline void DBFile::Read()
{
read(buf,str.lrd);
}
inline void DBFile::Write()
{
* buf = 32 ;
write(buf,str.lrd);
}
inline char * DBFile::Get( char * name, char * s)
{
return Get(FindField(name),s);
}
inline void DBFile::Put( char * name, const char * s)
{
Put(FindField(name),s);
}
inline void DBFile::Put( char * name, double s)
{
Put(FindField(name),s);
}
inline double DBFile:: operator []( char * name)
{
return atof(Get(name,str._nul));
}
inline double DBFile:: operator [](unsignedi)
{
return atof(Get(i,str._nul));
}
inline void DBFile::Seekp( long recnum)
{
seekp(recnum * str.lrd + str.ldb);
}
inline void DBFile::Seekg( long recnum)
{
seekg(recnum * str.lrd + str.ldb);
}
inline void DBFile::Delete( long recnum)
{
WriteDelFlag(recnum);
}
inline void DBFile::UnDelete( long recnum)
{
WriteDelFlag(recnum, 32 );
}
inline int DBFile::InRecords( long recnum)
{
return (recnum >= 0 && recnum < str.records);
}
#endif
DEFile类的CPP文件:
//
DBFILE.CPP
#include " dbfio.hpp "
#include < ctype.h >
void DBField::SetValue( char * n, int t, int w, int d)
{
strcpy(name,strupr(n));
type = toupper(t);
width = w;
dec = d;
}
void DBFile::Init()
{
fields = 0 ;
buf = 0 ;
}
void DBFile::SetFields( int n)
{
fields = n;
if (n)
{
dArray.SetLimit(n);
buf = new char [str.lrd + 1 ];
buf[ 0 ] = 32 ;
buf[str.lrd] = 0x1a ;
if ( ! buf || ! dArray.Items())
openerror = 6 ;
}
}
void DBFile::Close()
{
if (oldrecords != str.records)
{
seekp( 4 );
write(( char * ) & str.records, sizeof (unsigned long ));
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 ;
return s;
}
DBFile & DBFile:: operator >> ( long recnum)
{
if (InRecords(recnum))
{
Seekg(recnum);
Read();
}
else
memset(buf, 32 ,str.lrd);
return * this ;
}
void DBFile::WriteDelFlag( long recnum, int Flag)
{
Seekp(recnum);
write(( char * ) & Flag, 1 );
}
// DBFPUT.CPP
#include " dbfio.hpp "
#include < strstrea.h >
#include < iomanip.h >
#include < bcd.h >
void DBFile::Put(unsignedi, const char * s)
{
if (i < dArray.Count())
{
int flag = 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;
}
}
void DBFile::Put(unsignedi, double val)
{
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;
}
}
void DBFile::Append( int flag)
{
if ( ! flag)
memset(buf, 32 ,str.lrd);
Seekp(str.records);
Write();
str.records ++ ;
}
DBFile & DBFile:: operator << ( long recnum)
{
if (InRecords(recnum))
{
Seekp(recnum);
Write();
}
else
Append( 1 );
return * this ;
}
// DBFUSE.CPP
#include " dbfio.hpp "
DBFile::DBFile( const char * name):dArray( 0 , 1 )
{
Init();
Use(name);
}
void DBFile::Use( const char * 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 ( int i = 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( const char * name,DBField * fie, int n):dArray( 0 , 1 )
{
Init();
Use(name,fie,n);
}
void DBFile::Use( const char * name,DBField * fie, int n)
{
if ( ! fie || ! n)
{
openerror = 3 ;
return ;
}
if (fields)
Close();
openerror = 0 ;
str.lrd = 1 ;
for ( int i = 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 ( int i = 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();
}
#include " dbfio.hpp "
#include < ctype.h >
void DBField::SetValue( char * n, int t, int w, int d)
{
strcpy(name,strupr(n));
type = toupper(t);
width = w;
dec = d;
}
void DBFile::Init()
{
fields = 0 ;
buf = 0 ;
}
void DBFile::SetFields( int n)
{
fields = n;
if (n)
{
dArray.SetLimit(n);
buf = new char [str.lrd + 1 ];
buf[ 0 ] = 32 ;
buf[str.lrd] = 0x1a ;
if ( ! buf || ! dArray.Items())
openerror = 6 ;
}
}
void DBFile::Close()
{
if (oldrecords != str.records)
{
seekp( 4 );
write(( char * ) & str.records, sizeof (unsigned long ));
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 ;
return s;
}
DBFile & DBFile:: operator >> ( long recnum)
{
if (InRecords(recnum))
{
Seekg(recnum);
Read();
}
else
memset(buf, 32 ,str.lrd);
return * this ;
}
void DBFile::WriteDelFlag( long recnum, int Flag)
{
Seekp(recnum);
write(( char * ) & Flag, 1 );
}
// DBFPUT.CPP
#include " dbfio.hpp "
#include < strstrea.h >
#include < iomanip.h >
#include < bcd.h >
void DBFile::Put(unsignedi, const char * s)
{
if (i < dArray.Count())
{
int flag = 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;
}
}
void DBFile::Put(unsignedi, double val)
{
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;
}
}
void DBFile::Append( int flag)
{
if ( ! flag)
memset(buf, 32 ,str.lrd);
Seekp(str.records);
Write();
str.records ++ ;
}
DBFile & DBFile:: operator << ( long recnum)
{
if (InRecords(recnum))
{
Seekp(recnum);
Write();
}
else
Append( 1 );
return * this ;
}
// DBFUSE.CPP
#include " dbfio.hpp "
DBFile::DBFile( const char * name):dArray( 0 , 1 )
{
Init();
Use(name);
}
void DBFile::Use( const char * 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 ( int i = 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( const char * name,DBField * fie, int n):dArray( 0 , 1 )
{
Init();
Use(name,fie,n);
}
void DBFile::Use( const char * name,DBField * fie, int n)
{
if ( ! fie || ! n)
{
openerror = 3 ;
return ;
}
if (fields)
Close();
openerror = 0 ;
str.lrd = 1 ;
for ( int i = 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 ( int i = 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 < class T > class MArray
{
protected :
char * items; // 动态数组指针
int count; // 数组中对象个数
int limit; // 数组容量
int delta; // 数组增量
int typesize;
MArray(){}
void Init( int , int , int );
virtual T & Item( int index)
{
return * (T * ) & items[index * typesize];
}
virtual void Let( int index, const T * t)
{
memmove( & items[index * typesize],t,typesize);
}
public :
// 构造函数.参数:数组容量(个);增加量
MArray( int , int = 0 );
~ MArray();
void SetLimit( int );
// 移去一个对象,其后对象前移.参数:数组下标
void Remove( int );
// 移去指定位置及其后的所有对象;参数:数组下标
void RemoveAll( int = 0 );
// 增加对象到指定位置,其后对象后移,返回实际下标,出错返回0x7fff.
// 参数:数组下标;对象
int AddAt( int , const T & );
// 增加对象到数组尾部,返回实际的数组下标,出错返回0x7fff.参数:对象
int Add( const T & );
// 返回动态数组指针
char * Items();
// 查找对象,返回对象下标,未找到返回0X7FFF.参数:对象
int Find( const T & );
// 返回数组中的对象个数
int Count();
// 返回数组容量大小
int ArraySize();
// 返回对象的内存长度
int ObjectSize();
// 返回数组下标所指的对象,下标超范围时返回值不定