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, "\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 文件的读取.
来源: https://www.cnblogs.com/fan-0802-WHU/p/10150575.html