.shp文件的存储结构是怎样的?底层读取shapefile文件
.shp文件的存储结构是怎样的?底层读取shapefile文件
- 基础知识
- shp的存储结构
- python 字节流读取Shp文件
基础知识
大家都比较熟悉shp文件,它是GIS软件可以读取的矢量文件。但是大家知道它的存储结构吗?这次带着大家聊聊shp文件的存储结构,并尝试用python从底层读取一个点shp文件。
在此之前,需要大家了解一下字节和字节流的概念。
首先我们从最开始的二进制位讲起,二进制位就是计算机最最底层的语言,又可以表示为逻辑开(1)和关(0)。一位二进制位只能表示两种状态,要么是0,要么是1,但是如果多个二进制位组合在一起,那就可以表示很多状态(2^n)。另外我们都学过不同进制之间的转换,例如我们都会将10进制与2进制之间互相转换。
下面进入正题:我们将一个二进制位称为1bit,8bit,也就是8个二进制位构成一个字节。我们看一下一个字节可以表达的十进制范围
00000000(二进制)→0(十进制)
11111111(二进制)→255(十进制)
可以看到,一个字节可以表达256个数字,c语言中的char变量就是占用1个字节。另外,我们需要了解常见变量类型所占字节数,例如c语言中int整型变量占用4个字节,float类型占用4个字节,double占用8个字节。
实际上4个字节就可以表达很大的整数了,可以表达2^32个值,也就是4294967296个值,但通常整型加上正负号范围也就是:-2147483647~+2147483647,可以满足大部分需求,当然还有占用很多字节的长整型,可以占用8个字节(天文数字)。为了降低空间浪费,也有占用2个字节的短整型。
shp的存储结构
接下来我们就看一下shp的存储,对于非文本文件,例如图片和音视频,当然还包括各种乱七八糟的格式,我们需要以字节流的方式读取文件,而了解文件的存储结构是读取文件的基础。在用python读取之前,我们需要了解shapefile是如何字节存储的。
首先每个shp文件都有一个文件头,包括两部分内容:基本识别信息和空间信息概况,而且文件头的长度是固定的,一定包括100字节!文件头之后就是详细的空间记录信息。
文件头包括内容如下:
变量 | 类型 | 占用字节 |
---|---|---|
文件代码=9994 | int | 4 |
预留 | Int | 4 |
预留 | Int | 4 |
预留 | Int | 4 |
预留 | Int | 4 |
预留 | Int | 4 |
整个文件的长度(包括文件头,以双字节为单位) | int | 4 |
文件版本=1000 | Int | 4 |
几何体类型 | int | 4 |
所有X坐标最小值 | double | 8 |
所有Y坐标最小值 | double | 8 |
所有X坐标最大值 | double | 8 |
所有Y坐标最大值 | double | 8 |
所有Z坐标最小值 | double | 8 |
所有Z坐标最大值 | double | 8 |
所有M坐标最小值 | double | 8 |
所有M坐标最大值 | double | 8 |
合计 | 100 |
然后每个单独的空间记录信息都包括记录头和几何体记录信息两部分。其中,记录头共包括两个int类型,8个字节如下:
变量 | 类型 | 占用字节 |
---|---|---|
记录号 | Int | Int |
记录长度(这个记录长度是几何体记录信息,也就是不包括记录头的空间信息记录长度,以双字节为单位) | Int | 4 |
进一步,每个几何体记录信息分为两部分:shape类型(int类型,占用4字节)和空间坐标记录。
例如,最简单的,一个点坐标的记录固定占用20个字节,可以表示如下:
python 字节流读取Shp文件
下面开始用Python代码尝试用字节流读取shp文件!!!
首先,shp文件:
file_name= r'C:\Users\csh_g\Desktop\testdata\routeseg_ND_Junctions.shp'
然后,以二进制流读取模式打开文件:
f =open(file_name, "rb+")
python open() 函数打开文件的读取模式(参考菜鸟教程)
然后读取第一个4字节,这个变量是文件代码,一定等于9994:
readStream= f.read(4)
fileCode= struct.unpack('>i',readStream)[0]
printfileCode
其中,struct.unpack() 就是解包的意思,把二进制解包为某一类型变量。第一个参数’i’就指定了将其解包为整型。
- 拓展:另外可以看到,i前还有个>号,是因为该数值在shp文件中按照大端(Big-endian)位序存储,位序指的是一个数字的各个数位在内存中的排列顺序,通常的PC平台都采用小端(Little-endian)位序,而在网络传输中通常采用大端为序,因此在PC机上读取shp文件时,这些大端位序整数要进过位序转换才能得到正确的数值。
剩下的读取文件头就不一一阐述,注释中都有说明:
# 读掉5个预留int
f.read(5*4)# 文件长度
readStream = f.read(4)
fileLength = struct.unpack('>i',readStream)[0]
print fileLength# 文件版本
readStream = f.read(4)
fileVersion = struct.unpack('i',readStream)[0]
print fileVersion# 几何体类型
readStream = f.read(4)
shapeType = struct.unpack('i',readStream)[0]
print shapeType# 最小空间矩形
readStream = f.read(8)
XMin = struct.unpack('d', readStream)[0]
print XMin
readStream = f.read(8)
YMin = struct.unpack('d', readStream)[0]
print YMinreadStream = f.read(8)
XMax = struct.unpack('d', readStream)[0]
print XMax
readStream = f.read(8)
YMax = struct.unpack('d', readStream)[0]
print YMaxreadStream = f.read(8)
ZMin = struct.unpack('d', readStream)[0]
print ZMin
readStream = f.read(8)
ZMax = struct.unpack('d', readStream)[0]
print ZMaxreadStream = f.read(8)
MMin = struct.unpack('d', readStream)[0]
print MMin
readStream = f.read(8)
MMax = struct.unpack('d', readStream)[0]
print MMax
接下来就需要我们读取空间信息了,由于每个几何记录是不定长的,所以在读取的过程中必须借助文件头和每个空间记录信息的记录头里的记录长度,并写循环读取。
下面是读取过程:
# 定义变量剩余文件长度,总字节长度减去之前读的100字节
fileRemainingLen = fileLength * 2 - 100
# 存储几何体
all_records = []
while fileRemainingLen > 0:# 记录号readStream = f.read(4)recordID = struct.unpack('>i',readStream)[0]fileRemainingLen -= 4# 记录长度readStream = f.read(4)recordLen = struct.unpack('>i',readStream)[0]fileRemainingLen -= 4# 几何信息recordRemainingLen = recordLen * 2readStream = f.read(4)shapeType = struct.unpack('i',readStream)[0]fileRemainingLen -= 4recordRemainingLen -= 4if shapeType == 1: # 如果是点 # 存储单个几何体record = []while recordRemainingLen > 0:# 一个点readStream = f.read(8)x = struct.unpack('d',readStream)[0]recordRemainingLen -= 8fileRemainingLen -= 8readStream = f.read(8)y = struct.unpack('d',readStream)[0]recordRemainingLen -= 8fileRemainingLen -= 8record.append((x, y))all_records.append(record)
print all_records
以上就是读取点shape的过程,就是辣么简单,最终,我打印出来的结果是这样的:
9994
28792
1000
1
0.17388360826
0.110210912643
4679.59934183
3331.86113716
0.0
0.0
0.0
0.0
[[(0.17388360826021199, 0.11021091264308325)], [(0.17388360826021199, 212.24160359604684)], [(0.17388360826021199, 238.02255434822587)], [(0.17388360826021199, 351.05137534680057)],……
- shapeType对应空间几何类型:
编号 | 集合类型 |
---|---|
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(表示含有Measure值的点状目标) |
23 | PolygonM(表示含有Measure值的面状目标) |
25 | MultiPointZ(表示Shapefile文件记录的是三维点集合目标) |
28 | MultiPointM(表示含有Measure值的多点目标) |
以上是点shp图层的读取,即shapeType=1,存储结构最简单,相应读取也不麻烦,但若果是多义线,存储结构则更复杂,主要区别在于空间坐标记录部分。例如,多义线的空间坐标记录如下:
首先是前面4个double类型存储该要素的**最小包围矩形**;然后是**NumParts记录有多少分段**;然后是**NumPoints记录有多少坐标点**;然后是**Parts记录每个分段在坐标点集(Points)内的首点索引**;最后就是**Points坐标点集**了。
具体怎么读取大家可以尝试一下!!
- 拓展:为什么记录最小包围矩形?我们可以看到,无论是整个文件还是每个空间几何,都先都有最小包围矩形(minimum Bounding
rectangle,
MBR)。实际上这个MBR很有用处,尤其是空间数据量大的时候,我们做相交运算或查询操作,首先就是看MBR是否重合,只有MBR重合,才有可能两者相交或者在查询区域内。有了MBR就可以执行过滤-精简策略,很大程度上提高计算速度!
.shp文件的存储结构是怎样的?底层读取shapefile文件相关推荐
- Mysql原理解析 - 索引文件的存储结构
Mysql原理解析 - 索引文件的存储结构 前言 局部性原理 磁盘预读 索引是什么? 1. MSQL为什么索引选择B+树? 1.1 哈希表hash 简介: 局限性: 1.2 二叉树 简介: 局限性: ...
- Java使用GeoTools轻松读取shapefile文件内容
日常GIS开发中难免会将一些shapefile文件数据读取存入数据库中,很多人第一想到的就是使用GeoTools操作和显示地图的开源Java 代码库. 生活捉弄人,因为项目需要对于从来没有做过GIS相 ...
- shapefile java_JAVA读取SHAPEFILE文件的源代码.pdf
java读取ShapeFile文件的源代码 时间:2010-04-20 22:20来源: 作者:giser 点击: 70次 java读取ShapeFile文件的源代码 java读取ShapeFile文 ...
- android 图片文件流,Android 如何以流的方式读取图片文件
在读取sdcard中的图片文件时,如何以流的方式读取图片文件,请参阅下面的函数: public static void ShowImg(String uri, ImageView iv) throws ...
- ncl 添加点shp文件_一:python读取shapefile文件
使用geopandas读取shapefile格式的矢量文件 包括shapefile文件的读取.修改.保存 import geopandas as gpd # 导入包 segpath = r" ...
- Java使用GeoTools读取shapefile文件
文章目录 1.配置Maven仓库地址 2.引入pom依赖 3.创建与shape文件映射的实体类 4.创建读取ShapeFile的工具类 5.使用详解 1.配置Maven仓库地址 <reposit ...
- 服务器读取excel文件,关于c#:作为服务器进程读取Excel文件
我试图找到一种适当的方法来读取NT服务器操作系统上的Excel文件的内容. 我在使用Excel API时遇到许多问题,然后在Office Automation上遇到了正式的Microsoft,它指出E ...
- load python txt文件_详解Python中numpy.loadtxt()读取txt文件
为了方便使用和记忆,有时候我们会把 numpy.loadtxt() 缩写成np.loadtxt() ,本篇文章主要讲解用它来读取txt文件. 读取txt文件我们通常使用 numpy 中的 loadtx ...
- C#读取SHAPEFILE文件总结0--大纲
SHAPEFILE文件是地图文件的祖宗,学习怎么读取当然对学习很有裨益.在网上找了几篇资料,主要是百度文库里面看到个C#读取shapefile的DOC,就跟着抄代码学习一下. 现在刚好把point类型 ...
最新文章
- 2022-2028年中国新能源公交车行业深度调研及投资前景预测报告
- Java并发编程之:Vector和ArrayList的区别
- 优化mysql slave的同步速度
- Chisel 学习笔记(四)
- 孟菲斯风格海报设计素材,艺术一点点
- 大数据之-Hadoop之HDFS_HDFS的优缺点---大数据之hadoop工作笔记0049
- 法语学习笔记--第四课(家庭)
- 【poj3263】Tallest Cow(差分数组)
- Bash and a Tough Math Puzzle CodeForces 914D 线段树+gcd数论
- 无线通信原理期末复习提纲
- 【第五届集创赛备赛】三、紫光同创李星钢赛题解读直播要点总结
- android手势第一次设置密码_android实现手势密码
- 【英文】Node.js Streams: Everything you need to know //转载
- 7个无版权图库资源网站,全部高质量且免费,不愁找不到素材
- 淘淘商城——展示购物车商品列表
- 如何在Guitar Pro上添加吉他和弦
- Win10打开任务管理器卡死的解决方法
- 在滴滴数据分析岗实习的8个月
- 北京工业大学计算机考研录取名单,2018年硕士研究生招生考试复试一志愿考生名单(信息学部)...
- 升级鸿蒙要双清,在鸿蒙即将来临之际,先全方位进行一波升级,准备好了咩?...