php读取shp数据,shp系列(三)——利用C++进行DBF文件的读(打开)

1.DBF文件要点

DBF文件又叫属性文件,也叫dBASE文件,文件后缀是.dbf,实际上ArcGIS打开后的属性表就是DBF的信息。DBF文件遵循以下几个条件:每个要素在表中必须要包含一个与之相对应的记录。

记录的顺序必需与要素在主文件中(*.shp)的顺序一样。

dBASE 文件头中的年份值必须要晚于 1900 年。

2.DBF文件的组成

属性文件(.dbf)用于记录属性信息。它是一个标准的DBF文件,也是由头文件和实体信息两部分构成:

17899

3.DBF文件的头文件

文件头部分的长度是不定长的,它主要对DBF文件作了一些总体说明。

其中最主要的是对这个DBF文件的记录项(字段)的信息进行了详细地描述,比如对每个记录项(字段)的名称、数据类型、长度等信息都有具体的说明。

3.1头文件

17899date[3],BYTE,更新日期

verision,BYTE类型,版本信息

RecordNum,int,文件中记录条数

HeaderByteNum,short,文件头的字节数

RecordByteNum,short,一条记录的字节长度

Reserved1,short

Flag4s,BYTE

EncrypteFlag,BYTE

Unused[3],int,保留字节

MDXFlag,BYTE,MDX标识

LDriID,BYTE

Reserved2,short

RecordItem(记录项数组详情见下),32,字段描述信息

terminator,BYTE,终止标识

头文件的字节数为:1 + 1 * 3 + 4 + 2 + 2 + 2 + 1 + 1 + 4 * 3 + 1 + 1 + 2 + 32 * RecordNum + 1 = 33 + 32 * RecordNum

3.2记录项数组

记录项数组其实就是描述表中字段信息的数组

17899name[11],BYTE,字段名

fieldType,BYTE,字段类型,包括B、C、D、G、L、M和N

Reserved3,int

fieldLength,BYTE,记录项长度

decimalCount,BYTE,记录项精度

Reserved4,short

workID,BYTE

Reserved5[5],short,

mDXFflag1,BYTE

一个记录项字节数为:11 + 1 + 4 + 1 + 1 + 2 + 1 + 5 * 2 + 1 = 32

记录项描述信息中fieldType的类型说明

17899

4.实体信息

实体信息部分就是一条条属性记录,每条记录都是由若干个记录项(字段)构成,因此只要依次循环读取每条记录就可以了。

5.读取DBF代码

由于实际上每个shp文件的表的字段数可能不一样,并且每个字段的类型不固定,需要每次判定字段类型,然后根据不同类型设置来读取信息。可以根据字段数量设置一个数组,数组的每个元素存储对应顺序字段的类型,然后根据数组元素的值定义变量获取记录的信息。

上述想法是一种比较完善的做法,即对于任何数量和类型的字段都可以满足要求,也应该是ArcGIS读取表的方法。完善即代表需要考虑各种情况,费时费力。

这里根据实际情况,简化一下,读取已知字段数和字段类型的DBF的信息。

假设要读取一个八个字段的表:int类型:ObjectID,Ecrm,Elevt

double类型:shapeArea,shapeLength

CString类型:Dest,Ec,cc

代码如下

void readDbf(CString filename)

{

//****在读取shp之后打开DBF文件

int n = filename.ReverseFind('.');

filename = filename.Left(n);

filename = filename + ".dbf";

FILE* m_DbfFile_fp;//****Dbf文件指针

if ((m_DbfFile_fp = fopen(filename, "rb")) == NULL)//打开dbf文件

return;

//****读取dbf文件的文件头

int i, j;

BYTE version;

fread(&version, 1, 1, m_DbfFile_fp);

BYTE date[3];

for (i = 0; i<3; i++)

fread(date + i, 1, 1, m_DbfFile_fp);

int RecordNum;//文件中的记录条数

fread(&RecordNum, sizeof(int), 1, m_DbfFile_fp);

short HeaderByteNum;//文件头中的字节数

fread(&HeaderByteNum, sizeof(short), 1, m_DbfFile_fp);

short RecordByteNum;//一条记录中的字节长度

fread(&RecordByteNum, sizeof(short), 1, m_DbfFile_fp);

short Reserved1;

fread(&Reserved1, sizeof(short), 1, m_DbfFile_fp);

BYTE Flag4s;

fread(&Flag4s, sizeof(BYTE), 1, m_DbfFile_fp);

BYTE EncrypteFlag;

fread(&EncrypteFlag, sizeof(BYTE), 1, m_DbfFile_fp);

int Unused[3];

for (i = 0; i<3; i++)

fread(Unused + i, sizeof(int), 1, m_DbfFile_fp);

int a = Unused[0];

int b = Unused[1];

int c = Unused[2];

BYTE MDXFlag;

fread(&MDXFlag, sizeof(BYTE), 1, m_DbfFile_fp);

BYTE LDriID;

fread(&LDriID, sizeof(BYTE), 1, m_DbfFile_fp);

short Reserved2;

fread(&Reserved2, sizeof(short), 1, m_DbfFile_fp);

BYTE name[11];

BYTE fieldType;

int Reserved3;

BYTE fieldLength;

BYTE decimalCount;

short Reserved4;

BYTE workID;

short Reserved5[5];

BYTE mDXFlag1;

int fieldscount;

fieldscount = (HeaderByteNum - 32) / 32;

fieldscount_final = fieldscount;

//****读取记录项信息-共有8个记录项

for (i = 0; i< fieldscount; i++)//字段数

{

RecordItem recordItem; //定义记录项存储信息,便于写dbf使用

fread(name, 11, 1, m_DbfFile_fp); //FieldName----11   bytes

memcpy(recordItem.name, name, 11);

fread(&fieldType, sizeof(BYTE), 1, m_DbfFile_fp); //FieldType----1     bytes

recordItem.fieldType = fieldType;

fread(&Reserved3, sizeof(int), 1, m_DbfFile_fp); //Reserved3----4     bytes

recordItem.Reserved3 = Reserved3;

fread(&fieldLength, sizeof(BYTE), 1, m_DbfFile_fp); //FieldLength--1     bytes

recordItem.fieldLength = fieldLength;

fread(&decimalCount, sizeof(BYTE), 1, m_DbfFile_fp);//DecimalCount-1   bytes

recordItem.decimalCount = decimalCount;

fread(&Reserved4, sizeof(short), 1, m_DbfFile_fp); //Reserved4----2     bytes

recordItem.Reserved4 = Reserved4;

fread(&workID, sizeof(BYTE), 1, m_DbfFile_fp); //WorkID-------1    bytes

recordItem.workID = workID;

for (j = 0; j<5; j++) //Reserved5----10   bytes

fread(Reserved5 + j, sizeof(short), 1, m_DbfFile_fp);

memcpy(recordItem.Reserved5, Reserved5, 10);

fread(&mDXFlag1, sizeof(BYTE), 1, m_DbfFile_fp); //MDXFlag1-----1  bytes

recordItem.mDXFlag1 = mDXFlag1;

recordItems.push_back(recordItem);

}

BYTE terminator; //terminator----1 bytes

fread(&terminator, sizeof(BYTE), 1, m_DbfFile_fp);

//****读取dbf文件头结束

//****读取dbf文件记录  开始

int ObjectID, Ecrm, Elevt;

double shapeArea, shapeLength;

CString Dest, Ec, cc;

BYTE deleteFlag;

char media[40];

vector polygonAttribute;

vector ShapeArea;

vectortemp1;

for (i = 0; i

fread(&deleteFlag, sizeof(BYTE), 1, m_DbfFile_fp); //读取删除标记 1字节

//****读取 ObjectID int

for (j = 0; j<40; j++)

strcpy(media + j, "\0");

for (j = 0; j<10; j++)

fread(media + j, sizeof(char), 1, m_DbfFile_fp); //--10

ObjectID = atoi(media);

//****读取 Dest string

for (j = 0; j<40; j++)

strcpy(media + j, "\0");

for (j = 0; j<32; j++)

fread(media + j, sizeof(char), 1, m_DbfFile_fp); //--32

Dest = media;

//****读取 Ec string

for (j = 0; j<40; j++)

strcpy(media + j, "\0");

for (j = 0; j<16; j++)

fread(media + j, sizeof(char), 1, m_DbfFile_fp); //--16

Ec = media;//同上

//****读取 EcRm int

for (j = 0; j<40; j++)

strcpy(media + j, "\0");

for (j = 0; j<10; j++)

fread(media + j, sizeof(char), 1, m_DbfFile_fp); //--10

Ecrm = atoi(media);

//****读取 Elevt int

for (j = 0; j<40; j++)

strcpy(media + j, "\0");

for (j = 0; j<10; j++)

fread(media + j, sizeof(char), 1, m_DbfFile_fp); //--10

Elevt = atoi(media);

//****读取 Cc int

for (j = 0; j<40; j++)

strcpy(media + j, "\0");

for (j = 0; j<8; j++)

fread(media + j, sizeof(char), 1, m_DbfFile_fp); //--8

cc = media;//4值4''

//****读取 shape_length double

for (j = 0; j<40; j++)

strcpy(media + j, "\0");

for (j = 0; j<19; j++)

fread(media + j, sizeof(char), 1, m_DbfFile_fp); //--19

shapeLength = atof(media);//带e的

//****读取 shape_Area double

for (j = 0; j<40; j++)

strcpy(media + j, "\0");

for (j = 0; j<19; j++)

fread(media + j, sizeof(char), 1, m_DbfFile_fp); //--19

shapeArea = atof(media);

}

//****读取dbf文件记录  结束

}

这是在已知字段数和字段类型情况下读取的情况,如果未知的情况下,需要设置数组存储每个字段的类型,则数组的长度就是字段数量;在读取实体记录时,根据数组的每个元素的值设定对应类型的变量,来存储记录信息,必要时最后结果要转化(如字符型转化成整型)。这一部分大家可以自己去完善。

下一篇我们将讲述shx文件的读取。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值