Shape文件格式
一个ESRI的shapefile数据包含一个主文件(.shp),一个索引文件(.shx)和一个dBASE(.dbf)表。主文件是直接访问的,变长记录的文件,每一条记录都描述一个形状的一系列结点。在索引文件中,每一条记录包含主文件相应记录相对于主文件头的偏移量。dBASE表中每条记录表示一个要素的属性。这种几何结构和属性要素一对一的关系是通过记录号来控制的,表中的属性记录的顺序必须和主文件中的记录顺序相同。
Shapefile存储Integer和Double型的数据。Integer数据是有符号32位Integer(4字节),Double数据是有符号64位IEEEDouble浮点数据(8字节)。浮NumPoints必须是数字的值,正无穷、负无穷和非数字(NaN)值都是不允许的。不过,shapefile支持“无数据”的值,但是通常只能用于测量。任何小于-10(38)浮点数都被认为是“无数据”。
一、主文件:
主文件(.shp)包含一个定长的文件头,之后就是变长的记录。每一条变长的记录都是由一个定长的记录头和变长的记录内容组成的。Shapefile的内容分为两类:一是数据相关,包括主文件记录内容和主文件头的数据描述范围(形状类型,最小矩形外框等);二是文件管理相关,包括文件和记录的长度和记录的偏移量等。主文件中用于记录数据相关的Integer和DoubleInteger的字节序是little endian(PC或Intel),而用于文件管理相关的字节序则是big endian(Sun or Motorola)。
主文件头长度为100字节。下表列出文件头的字节位置、值、类型和字节序。
起始位置 | 字段名称 | 字段值 | 字段类型 | 字节序 |
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 | 最小Measrue值 | Double | Little |
92* | Mmax | 最大Measrue值 | Double | Little |
表1.shp文件的头文件结构
注:最后4个加星号特别标示的四个数据只有当这个Shapefile文件包含Z方向坐标或者具有Measrue值时才有值,否则为0.0。所谓Measrue值,是用于存储需要的附加数据,可以用来记录各种数据,例如权值、道路长度等信息。
文件长度是文件的所有长度,用16位字表示(即包括50个16位字长度的文件头)。
编号 | 几何类型 |
0 | Null Shape(表示这个Shapefile文件不含坐标) |
1 | Point(表示Shapefile文件记录的是点状目标,但不是多点) |
3 | PolyLine(表示Shapefile文件记录的是线状目标) |
5 | Polygon(表示Shapefile文件记录的是面状目标) |
8 | MultiPoint(表示Shapefile文件记录的是多点,即点集合) |
11 | PointZ(表示Shapefile文件记录的是三维点状目标) |
13 | PolyLineZ(表示Shapefile文件记录的是三维线状目标) |
15 | PolygonZ(表示Shapefile文件记录的是三维面状目标) |
18 | MultiPointZ(表示Shapefile文件记录的是三维点集合目标) |
21 | PointM(表示含有Measrue值的点状目标) |
23 | PolyLineM(表示含有Measrue值的线状目标) |
25 | PolygonM(表示含有Measrue值的面状目标) |
28 | MultiPointM(表示含有Measrue值的多点目标) |
31 | MultiPatch(表示复合目标) |
表2 shapefiles文件支持的几何类型
每一条记录的头保存该条记录的记录号和记录内容的长度(记录内容的长度不包括记录头的长度,其单位是字)。记录头是定长的,占8字节。前4字节Integer表示记录号,从1开始,字节序是Big;后4字节Integer表示记录内容长度,字节序是Big。内容长度只是内容的长度,用16位字表示。所以,每条记录的长度就是(4+内容长度)的16位字表示。
主文件的记录内容包含几何类型和几何数据。记录内容的长度取决于形状的部分和结点的数量,每一种几何类型有其相应的记录内容。如下:
(1)Null Shape:通常Null Shape是用来占位的,在shapefile创建时设置为 Null Shape,之后再添加几何数据。
起始位置 | 字段名称 | 字段值 | 数据类型 | 个数 | 字节序 |
Byte0 | 几何形状 | 0 | Integer | 1 | Little |
表3 Nullshape的内容表
(2)Point-X,Y空间的点:包括一对Double型的X,Y坐标值。
起始位置 | 字段名称 | 字段值 | 数据类型 | 个数 | 字节序 |
Byte0 | 几何形状 | 3 | Integer | 1 | Little |
Byte4 | X | X坐标值 | Double | 1 | Little |
Byte12 | Y | Y坐标值 | Double | 1 | Little |
表4 Point的内容表
(3)MultiPoint -X,Y空间的多点:是一个点集。包括边界框、点的个数和各个点的坐标。(注:所有的边界框都是以Xmin,Ymin,Xmax,Ymax的顺序存储的)
起始位置 | 字段名称 | 字段值 | 数据类型 | 个数 | 字节序 |
Byte | 几何形状 | 8 | Integer | 1 | Little |
Byte | 边界框 | 矩形定点值 | Double | 4 | Little |
Byte | 点数(NumPoints) | 点的个数 | Integer | 1 | Little |
Byte | 点集 | 各个点的坐标 | Point | 点的个数 | Little |
表5 MultiPoint的内容表
(4)PolyLine -X,Y空间的线状目标:是一个有序的顶点集合,包括一个或多个部分。部分是指连接两个或两个以上顶点的序列。部分可能会相连也可能不相连,可能相交也可能不相交。其记录内容包括边界框、部分数、点数、每个部分第一个点的索引序号和各个点的坐标。(注:x=44+4*NumParts)
起始位置 | 字段名称 | 字段值 | 数据类型 | 个数 | 字节序 |
Byte0 | 几何类型 | 3 | Integer | 1 | Little |
Byte4 | 边界框 | 矩形顶点值 | Double | 4 | Little |
Byte36 | 部分数 (Numparts) | 部分个数值 | Integer | 1 | Little |
Byte40 | 点数 (Numpoints) | 点的个数值 | Integer | 1 | Little |
Byte44 | 部分集 (Parts) | 每个部分第一点在点集中的序号 | Integer | 部分的个数 | Little |
x | 点集 (points) | 各个点的坐标 | Point | 点的个数 | Little |
表6 PolyLine的内容表
(5)Polygon -X,Y空间的面状目标:一个面状目标包含一个或多个环。环是一个首尾连接的由4个或4个以上的点组成的一个封闭的,非自交的环路。一个面状目标可能包含多重外环路。一个环的顶点顺序或方向显示了环是否位于面状目标的内部。内部环是逆时针的,而简单的环状面状目标通常是顺时针的。和线类似,面状目标也包括边界框、部分数、点数、每个部分(Parts)的第一个点的索引序号和各个点的坐标,只是面状目标中把环看做是部分(Parts)。
下面这个例子是一个包含一个内环的共有8个顶点的面状目标。对于面状目标类型有几点需要注意:
l 环是封闭的,也就是第一个和最后一个顶点必须是相同的。
l 每一个环的顶点组成的点的数组中,环的顺序是不重要的。
l 存储在shapefile中的多边形必须是“干净的”。这里干净的多边形是指:
Ø 不自交。就是说属于一个环的部分不能也属于另一个环。顶点可以共用,但环中的部分不能共用。
Ø 内部环是逆时针顺序的。“不干净的”多边形中内环的顺序也是顺时针的,会造成内部重叠。
以上图为例,该多边形部分个数为2,顶点个数为10。
部分:0(第一部分由v1、v2、v3、v4、v1组成,第一个顶点在点集中的序号为0)
5(第二部分由v5、v8、v7、v6、v5组成,第一个顶点在点集中的序号为5,且为内环,所以点的顺序是逆时针)
点集: v1 v2 v3 v4 v1 v5 v8 v7 v6 v5
(序号) 0 1 2 3 4 5 6 7 8 9
(其他的几何类型与此类似)
(注:x= x=44+4*部分的个数)
起始位置 | 字段名称 | 字段值 | 数据类型 | 个数 | 字节序 |
Byte0 | 几何类型 | 5 | Integer | 1 | Little |
Byte4 | 边界框 | 矩形顶点值 | Double | 4 | Little |
Byte36 | 部分数 (Numparts) | 部分的个数值 | Integer | 1 | Little |
Byte40 | NumPoints (Numpoints) | 点的个数值 | Integer | 1 | Little |
Byte44 | 部分集 (Parts) | 每个部分的第一点在点集中的序号 | Integer | 部分的个数 | Little |
x | 点集 (points) | 各个点的坐标 | Point | 点的个数 | Little |
表7 Polygon的内容表
(6)PointM- M型点:这种点有一个额外的坐标 M,注意"没有数据"的值可以被指定为M的一个值。 一个PointM的记录内容包括一对以X,Y顺序排列的Double的坐标,再加上MEASRUE值。
起始位置 | 字段名称 | 字段值 | 数据类型 | 个数 | 字节序 |
Byte0 | 几何类型 | 21 | Integer | 1 | Little |
Byte4 | X | X坐标值 | Double | 1 | Little |
Byte12 | Y | Y坐标值 | Double | 1 | Little |
Byte20 | M(Measure) | Measure值 | Double | 1 | Little |
表8 PointM的内容表
(7)MultiPointM -M型多点的纪录内容(注:X=40+point类型所占的字节数*点的个数)
起始位置 | 字段名称 | 字段值 | 数据类型 | 个数 | 字节序 |
Byte0 | 几何类型 | 28 | Integer | 1 | Little |
Byte4 | 边界框 | 矩形顶点值 | Double | 4 | Little |
Byte36 | NumPoints | 点的个数值 | Integer | 1 | Little |
Byte40 | 点集 | 各个点的坐标 | Point | 点的个数 | Little |
X | M最小值 | M的最小值 | Double | 1 | Little |
X+8 | M最大值 | M的最大值 | Double | 1 | Little |
X+16 | Marray | 各点的Measure值 | Double | 点的个数 | Little |
表9 MultiPointM的内容表
(8)PolyLineM -M型线状目标的记录内容(注:X=44+4*部分的个数,Y=X+point类型所占的字节数)
起始位置 | 字段名称 | 字段值 | 数据类型 | 个数 | 字节序 |
Byte0 | 几何类型 | 23 | Integer | 1 | Little |
Byte4 | 边界框 | 矩形顶点值 | Double | 4 | Little |
Byte36 | 部分数 | 部分的个数值 | Integer | 1 | Little |
Byte40 | NumPoints | 点的个数值 | Integer | 1 | Little |
Byte44 | 部分集 | 每个部分的第一点在点集中的序号 | Integer | 部分的个数 | Little |
X | 点集 | 各点的坐标值 | Point | 点的个数 | Little |
Y | M最小值 | M的最小值 | Double | 1 | Little |
Y+8 | M最大值 | M的最大值 | Double | 1 | Little |
Y+16 | Marray | 各点的Measure值 | Double | 点的个数 | Little |
表10 PolyLineM的内容表
(9)PolygonM- M型面状目标的记录内容(X,Y值同上)
起始位置 | 字段名称 | 字段值 | 数据类型 | 个数 | 字节序 |
Byte0 | 几何类型 | 25 | Integer | 1 | Little |
Byte4 | 边界框 | 矩形顶点值 | Double | 4 | Little |
Byte36 | 部分数 | 部分的个数值 | Integer | 1 | Little |
Byte40 | NumPoints | 点的个数值 | Integer | 1 | Little |
Byte44 | 部分集(Parts) | 每个部分的第一点在点集中的序号 | Integer | 部分的个数 | Little |
X | 点集 (Points) | 各点的坐标值 | Point | 点的个数 | Little |
Y | M最小值 | M的最小值 | Double | 1 | Little |
Y+8 | M最大值 | M的最大值 | Double | 1 | Little |
Y+16 | Marray | 各点的Measure值 | Double | 点的个数 | Little |
表11 PolygonM 的内容表
(10)PointZ- Z型点
起始位置 | 字段名称 | 字段值 | 数据类型 | 个数 | 字节序 |
Byte0 | 几何类型 | 11 | Integer | 1 | Little |
Byte4 | X | X坐标值
| Double | 1 | Little |
Byte12 | Y | Y坐标值 | Double | 1 | Little |
Byte20 | Z | Z坐标值 | Double | 1 | Little |
Byte28 | M | Measure值 | Double | 1 | Little |
表12 PointZ的记录内容
(11)Z型多点(暂没查到其内容表,但根据其它的我认为应与MultiPoint相同只是多了Z值和MEASRUE值)
(12)PolyLineZ -Z型线装目标
起始位置 | 字段名称 | 字段值 | 数据类型 | 个数 | 字节序 |
Byte0 | 几何类型 | 13 | Integer | 1 | Little |
Byte4 | 边界框 | 矩形的顶点值 | Double | 4 | Little |
Byte36 | NumParts | 部分(parts)的个数值 | Integer | 1 | Little |
Byte40 | NumPoints | 点的个数值 | Integer | 1 | Little |
Byte44 | 部分集(Parts) | 每个部分的第一点在点集中的序号 | Integer | NumParts | Little |
X | 点集(Points) | 各点的坐标值 | Point | NumPoints | Little |
Y | Zmin | Zmin | Double | 1 | Little |
Y+8 | Zmax | Zmax | Double | 1 | Little |
Y+16 | Zarray | 各点的z坐标值 | Double | NumPoints | Little |
Z | Mmax | Mmax | Double | 1 | Little |
Z+8 | Mmin | Mmin | Double | 1 | Little |
Z+16 | Marray | 各点的Measure值 | Double | NumPoints | Little |
表13 PolyLineZ的记录内容
注意:X=44+4* NumParts Y = X+(16* NumPoints)Z=Y+16+(8* NumPoints) *可选的多边形Z 一个多边形Z包含一个或多个环。一个环是四或多个点彼此相连组成的一个闭合的彼此不相交的环。一个多边形可能包括多个外环,一个多边形Z的环是被做为它的一部分的。
(13)PolygonZ -Z型面状目标
起始位置 | 字段名称 | 字段值 | 数据类型 | 个数 | 字节序 |
Byte0 | 几何类型 | 15 | Integer | 1 | Little |
Byte4 | 边界框 | 矩形的顶点值 | Double | 4 | Little |
Byte36 | NumParts | 部分(parts)的个数值 | Integer | 1 | Little |
Byte40 | NumPoints | 点的个数值 | Integer | 1 | Little |
Byte44 | Parts数组 | 每个部分的第一点在点集中的序号 | Integer | NumParts | Little |
X | Points数组 | 各点的坐标值 | Point | NumPoints | Little |
Y | Zmin | Zmin | Double | 1 | Little |
Y+8 | Zmax | Zmax | Double | 1 | Little |
Y+16 | Zarry | Zarry | Double | NumPoints | Little |
Z | Mmin | Mmax | Double | 1 | Little |
Z+8 | Mmax | Mmin | Double | 1 | Little |
Z+16 | Marry | Marry | Double | NumPoints | Little |
表14 PolygonZ的记录内容
一个MultiPatch 包括许多表面部分(parts)。每个表面部分(parts)描述了一个表面。部分类型是控制一个MultiPatch部分的vertices顺序是如何。
一个MultiPatch的部分(parts)可以是以下类型:
三角形条带 :三角形的连接条带,此处每个顶点(在开始二个后)完成一个新三角形。一个新三角形总是通过把新顶点和二个临近的原有点相连而得到。
三角形扇: 三角形的连接扇,此处每个顶点(在开始二个后)完成一个新三角形。一个新三角形总是通过把新顶点和一个个临近的原有点及这部分的第一个顶点相连而得到。
外环 : 多边形的外环。
内环 : 多边形的洞。
第一环 : 未定义类型的多边形的第一个环。
环 : 未定义类型的多边形的环。
一个简单的三角形条带或三角形扇代表一个简单的表面部分(parts)参见表14 看这些部分类型的例子。带环的部分的序列能描述有洞的多边形表面。该序列典型包括一个外环,代表部分(parts)的外边界,用许多内环代表洞。当用代表表现带洞的多边形部分(parts)环的集合的个体环是不知道,整个序列以第一环开始,接着是其他的环。不跟着第一环后的环的序列被认为是没有洞的外环的序列。
表14 MultiPatch 部分例子
用来对部分类型(PartsTypes)进行编码的值有:
值 | 0 | 1 | 2 | 3 | 4 | 5 |
部分类型 | 三角形条带 | 三角形扇 | 外环 | 内环 | 第一环 | 环 |
起始位置 | 字段名称 | 字段值 | 数据类型 | 个数 | 字节序 |
Byte0 | 几何类型 | 15 | Integer | 1 | Little |
Byte4 | 边界框 | 矩形的顶点值 | Double | 4 | Little |
Byte36 | NumParts | 部分(parts)的个数值 | Integer | 1 | Little |
Byte40 | NumPoints | 点的个数值 | Integer | 1 | Little |
Byte44 | Parts数组 | 每个部分的第一点在点集中的序号 | Integer | NumParts | Little |
X | PartsTypes数组 | 各部分的类型值 | Integer | NumParts | Little |
Y | Points数组 | 各点的坐标值 | Point | NumPoints | Little |
Z | Zmin | Zmin | Double | 1 | Little |
Z+8 | Zmax | Zmax | Double | 1 | Little |
Z+16 | Zarry | Zarry | Double | NumPoints | Little |
T | Mmin | Mmax | Double | 1 | Little |
T+8 | Mmax | Mmin | Double | 1 | Little |
T+16 | Marry | Marry | Double | NumPoints | Little |
表15 MultiPatch的记录内容
二、索引文件:
索引文件包括100字节的文件头和定长为8字节的若干条记录。
索引文件头中的文件长度也是用16位字(即两个字节)来计算的,所以其长度为(50+记录的条数乘以4)个字。
第I条索引记录存储其在主文件中的偏移量和主文件中该条记录的内容长度。如下表所示:
位置 | 字段 | 字段值 | 字段类型 | 字节序 |
0 | 偏移量 | 偏移量值 | Integer | Big |
4 | 内容长度 | 内容长度值 | Integer | Big |
注意:记录的偏移量是从主文件的开头到该条记录头的第一个字节的以16位字来计算的偏移量。所以,第一条记录的偏移量就是50,因为主文件有100字节的头。
三、dBASE文件
dBASE文件包括要素的属性或者让其他表可以连接的属性关键值。它的格式是标准的数据库文件格式。有4个要求:
l 文件名必须与主文件和索引文件的名字相同,文件名后缀必须是.dbf。
l 表中必须每一个要素都有一条记录。
l 记录的顺序必须和主文件中的要素记录的顺序相同。
l dBASE头中的年份值必须是1900年之后的。
1) 属性文件的文件头
其中文件头部分的长度是不定长的,它主要对DBF文件作了一些总体说明(见表)其中最主要的是对这个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表示记录项的个数。这个数组的结构在表17中有详细的解释。 |
X+1 | 1个字节 | 作为记录项终止标识。(终止的标记为0X0D) |
表16 .dbf文件的文件头
(注:X+2 到 X+264 范围内的263 个字节包含后链信息(相关数据库 (.dbc) 的相对路径)。如果第一个字节为 0x00,则该文件不与数据库关联。因此数据库文件本身总是包含 0x00。 )
位置 | 内容 | 说明 |
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 格式的索引文件,那么这个记录项为真,否则为空。 |
表17 .dbf文件记录项的信息描述
代码 | 数据类型 | 允许输入的数据 |
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) | 各种字符。 |
表18 .dbf文件中的数据类型
2) 属性文件的实体信息
实体信息部分就是一条条属性记录,每条记录都是由若干个记录项构成,因此只要依次循环读取每条记录就可以了。
可以用Ultra Edit查看shape文件的源代码。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义