十几年前,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
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();
}
DBFIle类所使用的动态数组模板类文件:
//
MARRAY.HPP
#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();
//
返回数组下标所指的对象,下标超范围时返回值不定
T
color:
分享到:
评论