十几年前,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
;
}
inline DBField
&
DBField::
operator
=
(
const
DBField
&
d )
{
memmove(
this
,
&
d,
sizeof
( DBField ) );
return
*
this
;
}
//
定义排序字段数组类
typedef MSArray
<
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;
unsigned ldb, lrd;
char
_nul[
20
];
}DBFSTRUCT;
DBFSTRUCT str;
char
*
buf;
DBField TmpField;
int
fields;
long
oldrecords;
int
openerror;
DBFieldArray dArray;
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;参数: 字段名
unsigned FindField(
char
*
);
//
返回字段排序数组
DBFieldArray
&
FieldArray();
//
给记录打上删除标记
void
Delete(
long
);
//
取消记录的删除标记
void
UnDelete(
long
);
//
如记录号在文件记录范围内返回 TRUE, 否则返回 FALSE
int
InRecords(
long
);
};
inline DBFile::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;
}
inline DBFieldArray
&
DBFile::FieldArray()
{
return
dArray;
}
inline
void
DBFile::Use()
{
Close();
}
inline DBFile::
~
DBFile()
{
Close();
}
inline
int
DBFile::OpenError()
{
return
openerror;
}
inline unsigned DBFile::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
[] ( unsigned i )
{
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( unsigned i,
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( unsigned i,
const
char
*
s )
{
if
( i
<
dArray.Count() )
{
int
flag
=
ios::left;
ostrstream os( 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( unsigned i,
double
val )
{
if
( i
<
dArray.Count() )
{
ostrstream os( buf, str.lrd );
bcd a( 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 )
{
DBField Field;
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
&
operator
[] (
int
);
};
template
<
class
T
>
inline MArray
<
T
>
::MArray(
int
mLimit,
int
mDelta )
{
Init( mLimit, mDelta,
sizeof
( T ) );
}
template
<
class
T
>
inline
void
MArray
<
T
>
::RemoveAll(
int
index )
{
if
( index
>=
0
&&
index
<
count )
count
=
index;
}
template
<
class
T
>
inline
char
*
MArray
<
T
>
::Items()
{
return
items;
}
template
<
class
T
>
inline
int
MArray
<
T
>
::Add(
const
T
&
t )
{
return
AddAt( count, t );
}
template
<
class
T
>
inline
int
MArray
<
T
>
::Count()
{
return
count;
}
template
<
class
T
>
inline
int
MArray
<
T
>
::ArraySize()
{
return
limit;
}
template
<
class
T
>
inline
int
MArray
<
T
>
::ObjectSize()
{
return
typesize;
}
template
<
class
T
>
inline T
&
MArray
<
T
>
::
operator
[] (
int
index )
{
return
Item( index );
}
#pragma
option -Jgx
template
<
class
T
>
void
MArray
<
T
>
::Init(
int
mLimit,
int
mDelta,
int
size )
{
items
=
0
;
count
=
0
;
limit
=
0
;
delta
=
mDelta;
typesize
=
size;
SetLimit( mLimit );
}
template
<
class
T
>
MArray
<
T
>
::
~
MArray()
{
if
( items )
delete[] items;
}
template
<
class
T
>
void
MArray
<
T
>
::SetLimit(
int
aLimit )
{
if
( aLimit
<=
limit )
return
;
if
( aLimit
>
0xfff0
/
typesize )
aLimit
=
0xfff0
/
typesize;
char
*
aItems
=
new
char
[aLimit
*
typesize];
if
( aItems )
{
if
( count )
memmove( aItems, items, count
*
typesize );
if
( items )
delete[] items;
items
=
aItems;
limit
=
aLimit;
}
}
template
<
class
T
>
void
MArray
<
T
>
::Remove(
int
index )
{
if
( index
<
0
||
index
>=
count )
return
;
count
--
;
if
( count )
memmove(
&
items[index
*
typesize],
&
items[( index
+
1
)
*
typesize], ( count
-
index )
*
typesize );
}
template
<
class
T
>
int
MArray
<
T
>
::AddAt(
int
index,
const
T
&
t )
{
if
( index
<
0
)
return
0x7fff
;
if
( count
==
limit )
SetLimit( count
+
delta );
if
( count
==
limit )
return
0x7fff
;
if
( index
<
count )
memmove(
&
items[( index
+
1
)
*
typesize],
&
items[index
*
typesize],
( count
-
index )
*
typesize
);
else
index
=
count;
Let( index,
&
t );
count
++
;
return
index;
}
template
<
class
T
>
int
MArray
<
T
>
::Find(
const
T
&
t )
{
for
(
int
i
=
0
; i
<
count; i
++
)
if
( Item( i )
==
t )
return
i;
return
0x7fff
;
}
#pragma
option -Jg
//
有序直接数组类模板.用户类中应定义默认构造函数和运算符 == 和 <.
template
<
class
T
>
class
MSArray :
public
virtual
MArray
<
T
>
{
protected
:
int
index;
//
搜索时保存的数组下标值
int
res;
//
搜索成功标记. 0 未找到匹配对象
int
duplicates;
//
允许重复插入标记
MSArray(){}
int
Search(
const
T
&
key );
public
:
//
构造函数.参数: 数组容量(个);增量;允许重复插入标记( 0 不允许重复 )
MSArray(
int
l,
int
d
=
0
,
int
u
=
0
);
//
将对象 t 按索引方式插到数组中,返回下标.如 t 属重复对象,
//
重复插入标记 != 0, t 被插入到相同对象的尾部,否则返回 0x7fff.
int
Add(
const
T
&
t );
//
用二分法查找第一个匹配对象, 返回数组下标, 无匹配对象返回 0x7fff.
int
Find(
const
T
&
t );
//
在Find()基础上,查找下一匹配对象,返回数组下标,无匹配对象返回 0x7fff.
int
FindNext();
//
返回使用 Find() 或 FindNext() 后 >= 关键对象的下标值
int
IndexNum()
{
return
index;
}
};
#pragma
option -Jgx
template
<
class
T
>
int
MSArray
<
T
>
::FindNext()
{
if
( res
&&
duplicates
&&
++
index
<
count
&&
Item( index
-
1
)
==
Item( index ) )
return
index;
res
=
0
;
return
0x7fff
;
}
template
<
class
T
>
int
MSArray
<
T
>
::Search(
const
T
&
key )
{
int
l
=
0
, i;
int
h
=
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;
return
res;
}
template
<
class
T
>
int
MSArray
<
T
>
::Add(
const
T
&
t )
{
int
i
=
Find( t );
if
( i
==
0x7fff
)
i
=
index;
else
{
if
(
!
duplicates )
return
0x7fff
;
for
( i
++
; Item( i )
==
t
&&
i
<
count; i
++
);
}
return
AddAt( i, t );
}
template
<
class
T
>
int
MSArray
<
T
>
::Find(
const
T
&
t )
{
if
( Search( t ) )
return
index;
return
0x7fff
;
}
template
<
class
T
>
MSArray
<
T
>
::MSArray(
int
l,
int
d,
int
u ) :
MArray
<
T
>
( l, d ),
duplicates( u ),
res(
0
)
{}
#pragma
option -Jg
//
无序间接数组类模板.退出时不删除对象本身,其余同 MArray<T> 类
template
<
class
T
>
class
IMArray :
public
virtual
MArray
<
T
>
{
protected
:
IMArray(){}
virtual
void
Let(
int
i,
const
T
*
t )
{
unsigned
long
p
=
( unsigned
long
)t;
memmove(
&
items[i
*
typesize],
&
p, typesize );
}
virtual
T
&
Item(
int
i )
{
return
*
( T
*
)(
*
(
long
*
)
&
items[i
*
typesize]);
}
public
:
IMArray(
int
Limit,
int
Delta
=
0
)
{
Init( Limit, Delta,
sizeof
( T
*
) );
}
};
//
有序间接数组类模板.退出时不删除对象本身.其余同 MSArray<T> 类
template
<
class
T
>
class
IMSArray :
public
MSArray
<
T
>
,
public
IMArray
<
T
>
{
protected
:
IMSArray(){}
public
:
IMSArray(
int
Limit,
int
Delta
=
0
,
int
u
=
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年前的东西,只能供初学者们借鉴参考。有错误或建议,请来信:[email protected]
更新:今天找了个以前DBFile类的测试代码,更新在此。另外补充说明一点:这个DBFile类用今天的眼光看,是比较简陋的,其中的方法也较低阶,一般数据文件操作方法如First、Last、Next、Bof、Eof等都没有。原因是当时使用C/C++的人,一般都不大喜欢dBASE,但是为了能读取当时大量的dbf文件的数据,写一个能读dbf文件,转换成自己的文件格式的代码就不错了,我这个类在当时已经是很完善了,不仅能读写,还能创建dbf文件。通过以前这个例子,不难看出,我们当时需要的只是文件转换,或者数字字段计算功能(对数字字段使用了[]重载,可以直接以字段名或字段序号操作)[2007-9-17 13:43P]。
#include
<
iostream.h
>
#include
"
DBFio.hpp
"
void
CreateDbf(
char
*
fileName)
{
DBField fields[
3
];
fields[
0
].SetValue(
"
Code
"
,
'
C
'
,
4
);
fields[
1
].SetValue(
"
Name
"
,
'
C
'
,
8
);
fields[
2
].SetValue(
"
Value
"
,
'
N
'
,
10
,
2
);
DBFile Dbf;
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();
}
void
main()
{
CreateDbf(
"
Test.dbf
"
);
DBFile dbf(
"
Test.dbf
"
);
char
code[
5
], name[
9
];
for
(
long
i
=
0
; i
<
dbf.Records(); i
++
)
{
dbf.Read();
dbf.Get(
"
Code
"
, code);
dbf.Get(
"
Name
"
, name);
cout
<<
code
<<
'
'
<<
name
<<
'
'
<<
dbf[
"
Value
"
]
<<
endl;
}
system(
"
pause
"
);
}
声明,文章的代码是1995年前的东西,只能供初学者们借鉴参考。有错误或建议,请来信:[email protected]