DBF的文件格式和C语言描述,表文件由头记录及数据记录组成。
DBF的文件格式和C语言描述,表文件由头记录及数据记录组成。
头记录定义该表的结构并包含与表相关的其他信息。头记录由文件位置 0 开始。
数据记录1紧接在头记录之后(连续的字节),包含字段中实际的文本。 记录的长度(以字节为单位)等于所有字段定义的长度之和。
表文件中存储整数时低位字节在前。
1.表头记录的结构:
字节偏移 说明 备注
0 文件类型 0x02 FoxBASE 0x03 FoxBASE+/dBASE III PLUS,无备注 0x30 Visual FoxPro 0x43 dBASE IV SQL 表文件,无备注 0x63 dBASE IV SQL 系统文件,无备注 0x83 FoxBASE+/dBASE III PLUS,有备注 0x8B dBASE IV 有备注 0xCB dBASE IV SQL 表文件,有备注 0xF5 FoxPro 2.x(或更早版本)有备注 0xFB FoxBASE
1 - 3 最近一次更新的时间 (YYMMDD)
4 - 7 文件中的记录数目
8 - 9 第一个数据记录的位置
10 - 11 每个数据记录的长度 (包括删除标记)
12 - 27 保留
28 表的标记 0x01 具有 .cdx 结构的文件 0x02 文件包含备注。 0x04 文件是数据库(.dbc) 请注意,这个字节可以包含任何上面值的和。例如,0x03 表明表具有结构化.cdx和一个备注字段。
29 代码页标记
30 - 31 保留,包含 0x00
32 - n 字段子记录 字段的数目决定了字段子记录的数目。表中每个字段都对应一个字段子记录。
n+1 头记录终止符(0x0D)
n+2- n+264 此范围内的 263 个字节包含后链信息(相关数据库 (.dbc) 的相对路径) 如果第一个字节为 0x00,则该文件不与数据库关联。
备注:头记录中的第 8 到第 9 个字节指示数据文件中数据的起始位置。数据记录从删除标记字节开始。如果此字节为 ASCII 空格 (0x20),该记录没有删除标记, 如果第一字节为星号 (0x2A),该记录有删除标记。在标记之后是字段记录中所命名各字段中的数据
2.字段子记录结构
字节偏移 说明 备注
0 - 10 字段名 最多 10 个字符 -若少于 10 则用空字符 (0x00) 填充
11 字段类型 C-字符型 Y-货币型 N-数值型 F-浮点型 D-日期型 T-日期时间型 B-双精度型 I-整型 L-逻辑型 M-备注型 G-通用型 C-字符型(二进制) M-备注型(二进制) P-图片型
12 - 15 记录中该字段的偏移量
16 字段长度 以字节为单位
17 小数位数
18 字段标记 0x01系统列(用户不可见) 0x02可存储 null 值的列 0x04二进制列(只适于字符型和备注型)
19 - 32 保留
格式保存的文件标头:
支持 null 值
日期时间型、货币型及双精度型数据
字符字段和备注字段标记为二进制
在数据库 (.dbc) 文件中添加表
提示:可以使用下面的公式求出表文件中字段的数目:(x - 296/32) 公式中,x 表示第一个记录的位置(表头记录的第 8 到第 9 个字节),296 表示 263(后链信息)+ 1(头记录终止符)+ 32(第一个字段子记录),32 是字段子记录的长度。
因为dbf文件的记录在文件数据部分,都是用ASCII码形式存放的,所以只要读出文件头和字段类型描述区的内容,就可以直接读取dbf文件中的每条记录,dbf文件头结构和字段类型描述结构用C语言表示如下:
struct dbf_head { /* DBF文件头结构 */
char vers; /* 版本标志*/
unsigned char yy,mm,dd; /* 最后更新年、月、日 */
unsigned long no_recs; /* 文件包含的总记录数 */
unsigned short head_len,rec_len; /* 文件头长度,记录长度 */
char reserved[20]; /* 保留 */
};
struct field_element{ /* 字段描述结构 */
char field_name[11]; /* 字段名称 */
char field_type; /* 字段类型 */
unsigned long offset; /* 偏移量 */
unsigned char field_length; /* 字段长度 */
unsigned char field_decimal; /* 浮点数整数部分长度 */
char reserved1[2]; /* 保留 */
char dbaseiv_id; /* dBASE IV work area id */
char reserved2[10]; /*
char production_index;
};
/************************************************************************************
COMMENTS:DBF文件的总体格式
a.数据记录部分,紧随结构描述部分,以ASCII码方式顺序存放,结束标志为1AH(即
文件结束标志),每条记录的首字节为删除标志,20H表示有效,2AH表示已被删除,
字段值间无分隔符,记录亦无结束标记.
b.结构描述部分,位于文件首部,以二进制方式存放,结束标志为0DH.长度
为32*(数据库的字段个数+1(即库整体描述))+1(0DH结束标志)
************************************************************************************/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
//DBF 文件头结构//即库整体描述表,共32个字节
typedef struct tagDBFFILEHEADER
{
unsigned char dfMark; //0x03h 或 0x80h(有MEMORY字段) 0
unsigned char dfYear,dfMmonth,dfDay; //依次为年月日,二进制 1-3
unsigned long dfRecordCount; //总记录个数,低位字节在前 4-7
unsigned short dfHeaderLength; //文件头长度=第9字节值*256+第8字节值 8-9
unsigned short dfRecordLength; //记录长度=第11字节值*256+第10字节值 10-11
unsigned char dfReserved[20]; //保留 12-31
}DBFFILEHEADER;
//DBF 字段结构//即字段描述表,32个字节/字段
typedef struct tagDBFINFOHEADER
{
unsigned char diFieldName[10]; //字段名称,ASCII码 0-9
unsigned char diReserved1; //保留字节 10
unsigned char diFieldType; //字段类型,CDNL等ASCII码 11
unsigned long diOffset; //本字段在首记录中的位置 12-15
unsigned char diFieldLength; //字段长度 <=256 16
unsigned char diDecimal; //小数点的位数 17
unsigned char diReserved[14]; //保留 18-31
}DBFINFOHEADER;
typedef DBFFILEHEADER *LPDBFFILEHEADER;
typedef DBFINFOHEADER *LPDBFINFOHEADER;
/************************************************************************************
CDBFFile class defination.
************************************************************************************/
class CDBFFile
{
public:
CDBFFile();
virtual ~CDBFFile();
long InitDbf(LPCTSTR lpszFilename); //填充FILEHEADER和INFOHEADER
int GetFieldCount();
int GetFieldLength(int FieldNum);
int GetDecimal(int FieldNum);
unsigned char * GetFieldName(int FieldNum);
unsigned char GetFieldType(int FieldNum);
long GetRecordCount();
int GetRecordLength();
int GetRecord(int RecordNum,unsigned char *pBuf);
int GetRecordFieldValue(int RecordNum,int FieldNum,unsigned char *pBuf);
unsigned long GetFieldColumSize(int fieldnum);
public:
unsigned char * m_Buffer;
DBFFILEHEADER m_FileHeader;
DBFINFOHEADER m_InfoHeader;
DWORD m_dwRecordLen;
};
/************************************************************************************
COMMENTS:CDBFFile实现文件
************************************************************************************/
#include "DBFFile.h "
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CDBFFile::CDBFFile()
{
m_Buffer = NULL;
}
CDBFFile::~CDBFFile()
{
if(m_Buffer) delete [] m_Buffer;
m_Buffer = NULL;
}
/************************************************************************************
FUNCTION: 初始化数据库
PARAMETER: [in] lpszFilename --- 指定要操作的DBF文件名
RETURN VALUE:void
************************************************************************************/
long CDBFFile::InitDbf(LPCTSTR lpszFilename)
{
HANDLE hFile;
DWORD dwFileSize, dwReadBytes;
DWORD dwErrCode;
hFile = CreateFile(lpszFilename, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile == INVALID_HANDLE_VALUE)
{
dwErrCode = GetLastError();
GetErrorMsg(dwErrCode, g_szErrMsg);
WriteLog( "Open DBF File failed!\x0D\x0A ", g_szErrMsg);
return -1;
}
dwFileSize = GetFileSize(hFile, NULL);
if(dwFileSize==0)
{
dwErrCode = GetLastError();
GetErrorMsg(dwErrCode, g_szErrMsg);
WriteLog( "Get File size failed!\x0D\x0A ", g_szErrMsg);
CloseHandle(hFile);
return -1;
}
if(m_Buffer)
{
delete [] m_Buffer;
m_Buffer = NULL;
}
m_Buffer = new unsigned char[dwFileSize];
if(!m_Buffer)
{
WriteLog( "Allocate memeory failed in InitDbf()!\x0D\x0A ", NULL);
CloseHandle(hFile);
return -1;
}
ReadFile(hFile, m_Buffer, dwFileSize, &dwReadBytes, NULL);
memcpy((void*)&m_FileHeader, m_Buffer, sizeof(DBFFILEHEADER));
m_dwRecordLen = m_FileHeader.dfRecordLength;
CloseHandle(hFile);
return 0;
}
/************************************************************************************
FUNCTION: 获取字段个数
PARAMETER: None
RETURN VALUE:字段个数
************************************************************************************/
int CDBFFile::GetFieldCount()
{
return(m_FileHeader.dfHeaderLength/32 - 1);
}
/************************************************************************************
FUNCTION: 获取任一字段名
PARAMETER: [in] FieldNum (base 1)
RETURN VALUE:字段名
************************************************************************************/
unsigned char * CDBFFile::GetFieldName(int FieldNum)
{
if (FieldNum < 1) return NULL;
unsigned char * p = &(m_Buffer[FieldNum * 32]);
memcpy(&m_InfoHeader, p, sizeof(m_InfoHeader));
return(m_InfoHeader.diFieldName);
}
/************************************************************************************
FUNCTION: 获取任一字段长度
PARAMETER: [in] FieldNum (base 1)
RETURN VALUE:字段长度
************************************************************************************/
int CDBFFile::GetFieldLength(int FieldNum)
{
if (FieldNum < 1) return -1;
unsigned char * p = &(m_Buffer[FieldNum * 32]);
memcpy(&m_InfoHeader, p, sizeof(m_InfoHeader));
return(m_InfoHeader.diFieldLength);
}
/************************************************************************************
FUNCTION: 获取任一字段类型
PARAMETER: [in] FieldNum (base 1)
RETURN VALUE:字段类型(A,N and so on)
************************************************************************************/
unsigned char CDBFFile::GetFieldType(int FieldNum)
{
if (FieldNum < 1) return '# ';
unsigned char * p = &(m_Buffer[FieldNum * 32]);
memcpy(&m_InfoHeader, p, sizeof(m_InfoHeader));
return(m_InfoHeader.diFieldType);
}
/************************************************************************************
FUNCTION: 获取任一数值型字段小数点位数
PARAMETER: [in] FieldNum (base 1)
RETURN VALUE:小数点位数
************************************************************************************/
int CDBFFile::GetDecimal(int FieldNum)
{
if (FieldNum < 1) return -1;
unsigned char * p = &(m_Buffer[FieldNum * 32]);
memcpy(&m_InfoHeader, p, sizeof(m_InfoHeader));
return(m_InfoHeader.diDecimal);
}
/************************************************************************************
FUNCTION: 获取记录个数
PARAMETER: None
RETURN VALUE:获取记录个数
************************************************************************************/
long CDBFFile::GetRecordCount()
{
return(m_FileHeader.dfRecordCount);
}
/************************************************************************************
FUNCTION: 获取记录长度
PARAMETER: None
RETURN VALUE:记录长度
************************************************************************************/
int CDBFFile::GetRecordLength()
{
return(m_FileHeader.dfRecordLength);
}
/************************************************************************************
FUNCTION: 获取任一记录内容
PARAMETER: [in] RecordNum (base 1)记录索引
[out] *pBuf 记录内容
RETURN VALUE:参数错误返回0
成功返回1
************************************************************************************/
int CDBFFile::GetRecord(int RecordNum,unsigned char *pBuf)
{
if (RecordNum < 1) return 0;
long lPos=m_FileHeader.dfHeaderLength + (RecordNum-1) * m_dwRecordLen;
//(DBFFILEHEADER+DBFINFOHEADER+头结束标志)+(RecordNum-1)*(记录长度)
unsigned char * p = &(m_Buffer[lPos]);
memcpy(pBuf, p, m_dwRecordLen);
return 1;
}
/************************************************************************************
FUNCTION: 获取任一记录的任一字段值
PARAMETER: [in] RecordNum (base 1)记录索引
[in] iFieldNum (base 1)字段索引
[out] *pBuf 记录内容
RETURN VALUE:参数错误返回0
成功返回1
************************************************************************************/
int CDBFFile::GetRecordFieldValue(int iRecordNum,int iFieldNum,unsigned char *pBuf)
{
char szLeft[100];
char szRight[100];
int i, iFieldLen, iBegin, iFieldCount;
memset(szLeft, 0, sizeof(szLeft));
memset(szRight, 0, sizeof(szRight));
iFieldCount = GetFieldCount();
if(iRecordNum < 1 || iFieldNum < 1 || iFieldNum> iFieldCount) return 0;
iFieldLen=GetFieldLength(iFieldNum);
int iOffset=1; //记录的删除标志2AH/20H
for (i=1; i <iFieldNum; i++)
{
iOffset+=GetFieldLength(i);
}
long lPos=iOffset + m_FileHeader.dfHeaderLength+(iRecordNum-1)*GetRecordLength();
unsigned char * p = &(m_Buffer[lPos]);
memcpy(pBuf, p, iFieldLen);
pBuf[iFieldLen]=0x0; //注意参数pBuf必须足够大(指定字段长度+1)
strcpy(szLeft, (char *)pBuf);
for(i=iFieldLen-1; i> =0; i--)
{
if(szLeft[i]= ' ') szLeft[i] = 0;
else break;
}
if(szLeft[0]==0)
{
strcpy((char *)pBuf, szLeft);
return 1;
}
for(i=0; i <iFieldLen; i++)
{
if(szLeft[i]!= ' ')
{
iBegin = i;
break;
}
}
memcpy(szRight, szLeft+iBegin, iFieldLen-iBegin);
strcpy((char *)pBuf, szRight);
return 1;
}
/************************************************************************************
FUNCTION: 获取字段宽度
PARAMETER: [in] iFieldNum (base 1)字段索引
RETURN VALUE:参数错误返回0
成功返回字段宽度
************************************************************************************/
unsigned long CDBFFile::GetFieldColumSize(int fieldnum)
{
int iFieldCount;
iFieldCount = GetFieldCount();
if (fieldnum < 1 || fieldnum> iFieldCount) return 0;
return GetFieldLength(fieldnum) * GetRecordCount();
}
posted on 2010-07-23 16:54 常州市润邦电子科技 阅读(1786) 评论(0) 编辑 收藏 举报