zoukankan      html  css  js  c++  java
  • shp系列(三)——利用C++进行DBF文件的读(打开)

    1.DBF文件要点

    DBF文件又叫属性文件,也叫dBASE文件,文件后缀是.dbf,实际上ArcGIS打开后的属性表就是DBF的信息。DBF文件遵循以下几个条件:

    • 每个要素在表中必须要包含一个与之相对应的记录。
    • 记录的顺序必须与要素在主文件中(*.shp)的顺序一样。
    • dBASE 文件头中的年份值必须要晚于 1900 年。

    2.DBF文件的组成

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

    3.DBF文件的头文件

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

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

    3.1头文件

    • date[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记录项数组

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

     

    • name[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的类型说明

    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<CString> polygonAttribute;
    	vector<double> ShapeArea;
    	vector<int>temp1;
    	
    	for (i = 0; i<RecordNum; i++) {
    		fread(&deleteFlag, sizeof(BYTE), 1, m_DbfFile_fp); //读取删除标记  1字节
    
    		//****读取 ObjectID int
    		for (j = 0; j<40; j++)
    			strcpy(media + j, "");
    		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, "");
    		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, "");
    		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, "");
    		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, "");
    		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, "");
    		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, "");
    		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, "");
    		for (j = 0; j<19; j++)
    			fread(media + j, sizeof(char), 1, m_DbfFile_fp);   //--19
    		shapeArea = atof(media);
    	}
    	//****读取dbf文件记录  结束
    }
    

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

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

  • 相关阅读:
    hdu6055(求正方形个数)
    树状数组模板(改点求段 / 该段求点 / 改段求段)
    poj2763(lca / RMQ + 线段树)
    poj3728(lca / tarjan离线)
    JDK8-废弃永久代(PermGen)迎来元空间(Metaspace)
    JVM垃圾回收机制
    虚拟机字节码执行引擎
    Java中程序初始化的顺序
    Java中ClassLoader浅析.
    Python中的self
  • 原文地址:https://www.cnblogs.com/fan-0802-WHU/p/10150575.html
Copyright © 2011-2022 走看看