Shapefile格式说明及读写代码示例
Shape Files 数据说明
Shape Files 是 ESRI 提供的一种矢量数据格式,它没有拓扑信息,一个 Shape files 由一组文件组成,其中必要的基本文件包括坐标文件( .shp )、索引文件( .shx )和属性文件( .dbf )三个文件。
坐标文件的结构说明
坐标文件 (.shp) 用于记录空间坐标信息。它由头文件和实体信息两部分构成(如图 2.1 所示)。
坐标文件的文件头
坐标文件的文件头是一个长度固定 (100 bytes) 的记录段,一共有 9 个 int 型和 7 个 double 型数据,主要记录
见
2.2 。
文件头
记录头
记录内容
记录头
记录内容
记录头
记录内容
记录头
记录内容
图 2.1 坐标文件的结构
起始位置
名称
数值
类型
位序
0
File Code
9994
Integer
big
4
Unused
0
Integer
big
8
Unused
0
Integer
big
12
Unused
0
Integer
big
16
Unused
0
Integer
big
20
Unused
0
Integer
big
24
文件长度
文件的实际长度
Integer
big
28
版本号
1000
Integer
Little
32
几何类型
表示这个 ShapeFile 文件所记录的空间数据的几何类型
Integer
Little
36
Xmin
空间数据所占空间范围的 X 方向最小值
Double
Little
44
Ymin
空间数据所占空间范围的 Y 方向最小值
Double
Little
52
Xmax
空间数据所占空间范围的 X 方向最大值
Double
Little
60
Ymax
空间数据所占空间范围的 Y 方向最大值
Double
Little
68*
Zmin
空间数据所占空间范围的 Z 方向最小值
Double
Little
76*
Zmax
空间数据所占空间范围的 Z 方向最大值
Double
Little
84*
Mmin
最小 Measure 值
Double
Little
92*
Mmax
最大 Measure 值
Double
Little
表 2.2shapefiles 头文件表
注:最后 4 个加星号特别标示的四个数据只有当这个 Shapefile 文件包含 Z 方向 坐标或者具有 Measure 值时才有值,否则为 0.0 。所谓 Measure 值,是用于存储需要的 附加数据,可以用来记录各种数据,例如权值、道路长度等信息。
位序
细心的读者会注意到表 2.2 中的数值的位序有 Little 和 big 的区别,对于位序是 big 的数据我们在读取时要小心。通常,数据的位序都是 Little ,但在有些情况下可能会是 big ,二者的区别在于它们位序的顺序相反。一个位序为 big 的数据,如果我们想得到它的真实数值,需要将它的位序转换成 Little 即可。转换原理非常简单,就是交换字节顺序,下面是作者实现的在两者间进行转换的程序,代码如下:
// 位序转换程序
unsigned long OnChangeByteOrder (int indata)
{
char ss[8];
char ee[8];
unsigned long val = unsigned long(indata);
_ultoa( val, ss, 16 );// 将十六进制的数 (val) 转到一个字符串 (ss) 中
int i;
int length=strlen(ss);
if(length!=8)
{
for(i=0;i<8-length;i++)
ee[i]='0';
for(i=0;i
标准的 DBF 文件,也是由头文件和实体信息两部分构成。
文件头
记录 1
记录 2
记录 3
记录 4
……
记录 n
属性文件的文件头
其中文件头部分的长度是不定长的,它主要对 DBF 文件作了一些总体说明(见表 2.7 ),其中最主要的是对这个 DBF 文件的记录项的信息进行了详细地描述,比如对每个记录项的名称、数据类型、长度等信息都有具体的说明。
在文件中的位置
内容
说明
0
1 个字节
表示当前的版本信息
1 - 3
3 个字节
表示最近的更新日期,按照 YYMMDD 格式。
4 - 7
1 个 32 位数
文件中的记录条数。
8 - 9
1 个 16 位数
文件头中的字节数。
10 - 11
1 个 16 位数
一条记录中的字节长度。
12 - 13
2 个字节
保留字节,用于以后添加新的说明性信息时使用,这里用 0 来填写。
14
1 个字节
表示未完成的操作。
15
1 个字节
dBASE IV 编密码标记。
16 - 27
12 个字节
保留字节,用于多用户处理时使用。
28
1 个字节
DBF 文件的 MDX 标识。在创建一个 DBF 表时,如果使用了 MDX 格式的索引文件,那么 DBF 表的表头中的这个字节就自动被设置了一个标志,当你下次试图重新打开这个 DBF 表的时候,数据引擎会自动识别这个标志,如果此标志为真,则数据引擎将试图打开相应的 MDX 文件。
29
1 个字节
Language driver ID.
30 - 31
2 个字节
保留字节,用于以后添加新的说明性信息时使用,这里用 0 来填写。
32 - X
( n*32 )个字节
记录项信息描述数组。 n 表示记录项的个数。这个数组的结构在表 2.8 中有详细的解释。
X + 1
1 个字节
作为记录项终止标识。
表 2.7 属性文件( .dbf )的文件头
位置
内容
说明
0 - 10
11 个字节
记录项名称,是 ASCII 码值。
11
1 个字节
记录项的数据类型,是 ASCII 码值。( B 、 C 、 D 、 G 、 L 、 M 和 N ,具体的解释见表 2.9 )。
12 - 15
4 个字节
保留字节,用于以后添加新的说明性信息时使用,这里用 0 来填写。
16
1 个字节
记录项长度,二进制型。
17
1 个字节
记录项的精度,二进制型。
18 - 19
2 个字节
保留字节,用于以后添加新的说明性信息时使用,这里用 0 来填写。
20
1 个字节
工作区 ID 。
21 - 30
10 个字节
保留字节,用于以后添加新的说明性信息时使用,这里用 0 来填写。
31
1 个字节
MDX 标识。如果存在一个 MDX 格式的索引文件,那么这个记录项为真,否则为空。
表 2.8 记录项信息描述
代码
数据类型
允许输入的数据
B
二进制型
各种字符。
C
字符型
各种字符。
D
日期型
用于区分年、月、日的数字和一个字符,内部存储按照 YYYYMMDD 格式。
G
(General
or OLE)
各种字符。
N
数值型 (Numeric)
- . 0 1 2 3 4 5 6 7 8 9
L
逻辑型( Logical )
? Y y N n T t F f (? 表示没有初始化 ) 。
M
(Memo)
各种字符。
属性文件的实体信息
实体信息部分就是一条条属性记录,每条记录都是由若干个记录项构成,因此只要依次循环读取每条记录就可以了。
一个读取 dbf 文件的例子
假设要读取一个名为 soil 的 dbf 文件(存储了土地利用信息),它含有 8 个记录项,记录项信息如表 2.10 所示:
记录项名称
数据类型
长度
小数位数
Area
数值型( double )
31
15
Perimeter
数值型( double )
31
15
soils_
数值型( int )
11
0
soils_id
数值型( int )
11
0
soil_code
字符型( character )
3
无
Suit
字符型( character )
1
无
Centroid_x
数值型( double )
31
15
Centroid_y
数值型( double )
31
15
表 2.10dbf 文件中的数据类型
下面是读取这个 dbf 文件的代码:
void OnReadDbf(CString DbffileName)
{
File* m_DbfFile_fp; //****Dbf 文件指针
// 打开 dbf 文件
if((m_Dbffile_fp=fopen(DbfFileName,"rb"))==NULL)
{
return;
}
int i,j;
//////**** 读取 dbf 文件的文件头 开始
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);
for(i=0;i<3;i++)
{
fread(&Unused, sizeof(int), 1,m_DbfFile_fp);
}
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;
// 读取记录项信息-共有 8 个记录项
for(i=0;i< HeaderByteNum;i++)
{
//FieldName----11 bytes
fread(name, 11, 1,m_Dbffile_fp);
//FieldType----1 bytes
fread(&fieldType, sizeof(BYTE), 1,m_DbfFile_fp);
//Reserved3----4 bytes
Reserved3 =0;
fread(&Reserved3, sizeof(int), 1,m_DbfFile_fp);
//FieldLength--1 bytes
fread(&fieldLength,sizeof(BYTE), 1,m_Dbffile_fp);
//DecimalCount-1 bytes
fread(&decimalCount,sizeof(BYTE), 1,m_DbfFile_fp);
//Reserved4----2 bytes
Reserved4 =0;
fread(&Reserved4, sizeof(short), 1,m_DbfFile_fp);
//WorkID-------1 bytes
fread(&workID, sizeof(BYTE), 1,m_DbfFile_fp);
//Reserved5----10 bytes
for(j=0;j<5;j++)
{
fread(Reserved5+j,sizeof(short), 1,m_Dbffile_fp);
}
//MDXFlag1-----1 bytes
fread(&mDXFlag1, sizeof(BYTE), 1,m_DbfFile_fp);
}
BYTE terminator;
fread(&terminator,
sizeof(BYTE), 1,m_DbfFile_fp); // 读取 dbf 文件头结束
double Area,Perimeter,Centroid_y,Centroid_x;
int Soils_,Soils_id;
CString Soil_code,suit;
BYTE deleteFlag;
char media[31];
// 读取 dbf 文件记录 开始
for(i=0;i