.shp文件的存储结构是怎样的?底层读取shapefile文件

news2024/11/24 2:36:13

.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字节!文件头之后就是详细的空间记录信息

文件头包括内容如下:

变量类型占用字节
文件代码=9994int4
预留Int4
预留Int4
预留Int4
预留Int4
预留Int4
整个文件的长度(包括文件头,以双字节为单位)int4
文件版本=1000Int4
几何体类型int4
所有X坐标最小值double8
所有Y坐标最小值double8
所有X坐标最大值double8
所有Y坐标最大值double8
所有Z坐标最小值double8
所有Z坐标最大值double8
所有M坐标最小值double8
所有M坐标最大值double8
合计100

然后每个单独的空间记录信息都包括记录头几何体记录信息两部分。其中,记录头共包括两个int类型,8个字节如下:

变量类型占用字节
记录号IntInt
记录长度(这个记录长度是几何体记录信息,也就是不包括记录头的空间信息记录长度,以双字节为单位)Int4

进一步,每个几何体记录信息分为两部分: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 YMin

readStream = f.read(8)
XMax = struct.unpack('d', readStream)[0]
print XMax
readStream = f.read(8)
YMax = struct.unpack('d', readStream)[0]
print YMax

readStream = f.read(8)
ZMin = struct.unpack('d', readStream)[0]
print ZMin
readStream = f.read(8)
ZMax = struct.unpack('d', readStream)[0]
print ZMax

readStream = 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 * 2
    readStream = f.read(4)
    shapeType = struct.unpack('i',readStream)[0]
    fileRemainingLen -= 4
    recordRemainingLen -= 4
    if shapeType == 1:  # 如果是点    
        # 存储单个几何体
        record = []
        while recordRemainingLen > 0:
            # 一个点
            readStream = f.read(8)
            x = struct.unpack('d',readStream)[0]
            recordRemainingLen -= 8
            fileRemainingLen -= 8

            readStream = f.read(8)
            y = struct.unpack('d',readStream)[0]
            recordRemainingLen -= 8
            fileRemainingLen -= 8

            record.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对应空间几何类型:
编号集合类型
0Null Shape(表示这个Shapefile文件不含坐标)
1Point(表示Shapefile文件记录的是点状目标,但不是多点)
3Polyline(表示Shapefile文件记录的是线状目标)
5Polygon(表示Shapefile文件记录的是面状目标)
8MultiPoint(表示Shapefile文件记录的是多点,即点集合)
11PointZ(表示Shapefile文件记录的是三维点状目标)
13PolylineZ(表示Shapefile文件记录的是三维线状目标)
15PolygonZ(表示Shapefile文件记录的是三维面状目标)
18MultiPointZ(表示Shapefile文件记录的是三维点集合目标)
21PointM(表示含有Measure值的点状目标)
23PolygonM(表示含有Measure值的面状目标)
25MultiPointZ(表示Shapefile文件记录的是三维点集合目标)
28MultiPointM(表示含有Measure值的多点目标)

以上是点shp图层的读取,即shapeType=1,存储结构最简单,相应读取也不麻烦,但若果是多义线,存储结构则更复杂,主要区别在于空间坐标记录部分。例如,多义线的空间坐标记录如下:

首先是前面4个double类型存储该要素的**最小包围矩形**;然后是**NumParts记录有多少分段**;然后是**NumPoints记录有多少坐标点**;然后是**Parts记录每个分段在坐标点集(Points)内的首点索引**;最后就是**Points坐标点集**了。

具体怎么读取大家可以尝试一下!!

  • 拓展:为什么记录最小包围矩形?我们可以看到,无论是整个文件还是每个空间几何,都先都有最小包围矩形(minimum Bounding
    rectangle,
    MBR)。实际上这个MBR很有用处,尤其是空间数据量大的时候,我们做相交运算或查询操作,首先就是看MBR是否重合,只有MBR重合,才有可能两者相交或者在查询区域内。有了MBR就可以执行过滤-精简策略,很大程度上提高计算速度!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/169771.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux diff 命令

Linux diff 命令用于比较文件的差异。diff 以逐行的方式&#xff0c;比较文本文件的异同处。如果指定要比较目录&#xff0c;则 diff 会比较目录中相同文件名的文件&#xff0c;但不会比较其中子目录。语法diff [-abBcdefHilnNpPqrstTuvwy][-<行数>][-C <行数>][-D…

【Java】【系列篇】【Spring源码解析】【三】【体系】【Resource体系】

主要用于加载配置资源等等Resource 前提须知 ClassLoader类的getResource和getResourceAsStream方法是原生JDK中内置的资源加载文件的方式&#xff1b;Spring中资源模型顶级接口不是Resource&#xff0c;而是InputStreamSource接口&#xff1b;Spring为何自己实现一套资源加载…

Nessus 扫描web服务

系列文章 Nessus介绍与安装 Nessus Host Discovery Nessus 高级扫描 Nessus 扫描web服务 1.启动nessus cd nessus sh qd_nessus.sh2.进入nessus网站 https://192.168.3.47:8834/3.点击【New Scan】 4.点击【Web应用程序测试】 5.输入name【web扫描】&#xff0c;描述【web…

Lesson 2. 矩阵运算基础、矩阵求导与最小二乘法

文章目录一、NumPy 矩阵运算基础1. NumPy 中的矩阵表示2. NumPy 中特殊矩阵构造方法3. NumPy 中矩阵基本运算4. NumPy 中矩阵代数运算二、矩阵方程与向量求导方法1. 方程组求解与矩阵方程求解2. 向量求导运算2.1 向量求导基本方法2.2 常见向量求导公式三、最小二乘法的推导过程…

Vue3 函数式组件的开发方式

声明式组件和服务式组件 无论是使用第三方组件库&#xff0c;还是自己封装组件&#xff0c;有一类组件有些与众不同&#xff0c;那就是函数式/服务式组件&#xff0c;比如 Message 消息组件、Notification 通知组件、Loading 加载组件等等。 以 ElementPlus 组件库为例&#…

.net反序列化新手入门--Json.Net

**01 **Json.net简介 Json.net即Newtonsoft.Json&#xff0c;是.Net中开源的Json序列化和反序列化工具&#xff0c;官方地址&#xff1a;http://www.newtonsoft.com/json。 它虽然不是官方库&#xff0c;但凭借其优秀的性能获得了广大开发者的喜爱。 官网给出的性能比较&…

8大预测分析工具比较

什么是预测分析工具&#xff1f; 预测分析工具融合了人工智能和业务报告。这些工具包括用于从整个企业收集数据的复杂管道&#xff0c;添加统计分析和机器学习层以对未来进行预测&#xff0c;并将这些见解提炼成有用的摘要&#xff0c;以便业务用户可以对此采取行动。 预测的…

day17集合

1.Set集合 1.1Set集合概述和特点【应用】 不可以存储重复元素没有索引,不能使用普通for循环遍历 1.2Set集合的使用【应用】 存储字符串并遍历 public class MySet1 {public static void main(String[] args) {//创建集合对象Set<String> set new TreeSet<>()…

超级详细的几道python题(附答案)含解析、建议收藏

名字&#xff1a;阿玥的小东东 学习&#xff1a;python、正在学习c 主页&#xff1a;阿玥的小东东 目录 判断字符串 a “welcome to my world” 是否包含单词 b “world”&#xff0c;包含返回 True&#xff0c;不包含返回 False。 从 0 开始计数&#xff0c;输出指定字符串…

SSH使用入门

目录 .1 基础配置 1.1 vscode使用 1.2 HOST连接 .2 文件传输 .1 基础配置 1.1 vscode使用 拓展里搜索 然后点击remote里的设置 选择配置 然后填写配置 Hostname是你要ssh的服务器的ip地址 user是你要连接的服务器的用户名 Host可以随便写一个 如果有端口号也要对应修改 …

对于KMP的next数组的新发现,好像我们并不用回溯

目录 前言 发现 总结 博客主页&#xff1a;张栩睿的博客主页 欢迎关注&#xff1a;点赞收藏留言 系列专栏&#xff1a;c语言学习 家人们写博客真的很花时间的&#xff0c;你们的点赞和关注对我真的很重要&#xff0c;希望各位路过的朋友们能多多点赞并关注我&#xff0c;我会…

datax数据导入starrocks表报列数量不匹配错误,问题解决思路

背景在做客户数据导入任务的时候&#xff0c;需要将客户oracle的数据通过datax导入到 starrocks的表中&#xff0c;但是datax的配置文件中SQL查找客户数据的列数和要导入的starrocks表的列数都是相同且对应的&#xff0c;但是导入结果就是报了列数不对等的错误&#xff0c;Erro…

把代码贴进去自动找bug,这个debug神器自动修复仅需几秒

在编写程序时&#xff0c;无论是对于初学者还是对于专业开发人员&#xff0c;都会花费大量时间来调试或修复源代码错误&#xff0c;也就是 Debug。 这个过程繁琐复杂&#xff0c;包括 Bug 复现和 Bug 定位等环节。如果有了自动化的 Debug 程序&#xff0c;就可以显著提高编程实…

网络文件服务器:FileVista 8.9.3 Crack

FileVista 用于自托管文件共享的FileVista文件管理器 在几分钟内将您的网站变成一个网络文件服务器。 在您的网站上与您的客户或员工共享文件。 将您的机密文件存储在您自己的服务器上并对其进行完全控制。使您的用户只需使用 Web 浏览器即可从任何地方安全地访问、上传和组织文…

深度学习入门基础CNN系列——感受野和多输入通道、多输出通道以及批量操作基本概念

本篇文章主要讲解卷积神经网络中的感受野和通道的基本概念&#xff0c;适合于准备入门深度学习的小白&#xff0c;也可以在学完深度学习后将其作为温习。 如果对卷积计算没有概念的可以看本博主的上篇文章深度学习入门基础CNN系列——卷积计算 一、感受野&#xff08;receptive…

基于Java+SpringBoot+Vue+uniapp微信小程序零食商城系统设计和实现

博主介绍&#xff1a;✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

【从零开始学习深度学习】47. Pytorch图片样式迁移实战:将一张图片样式迁移至另一张图片,创作自己喜欢风格的图片【含完整源码】

目录1. 图片样式迁移的方法介绍2. 读取内容图像和样式图像3. 图像的预处理和后处理4. 图像的抽取特征5.1 内容损失5.2 样式损失5.3 总变差损失5.4 损失函数6. 创建和初始化合成图像7. 训练模型并输出合成图像总结本文将介绍如何使用卷积神经网络自动将某图像中的样式应用在另一…

分享回顾|新岁序开,2023 和Jina AI共同码梦!

在坚持开放协作精神、具备全球影响力的 Jina AI 开源社区&#xff0c;每天都有来自世界各地的开发者来到这里&#xff0c;因为技术产生联结&#xff0c;因为联结产生共创。一直以来&#xff0c;我们都为拥有这样一个全球化、多元化和高速发展的社区而感到自豪和感激&#xff01…

golang解决跨域问题

文章目录前言一、跨域问题1.是什么2.跨域的特征&#xff08;跨域报错&#xff09;二、解决跨域问题的方法1.golang解决跨域问题2.简单请求3.非简单请求过程分析&#xff08;复杂请求&#xff09;:三、状态码设置为200依旧出错前言 今天中午在部署golang与vue搭建的一个项目时&…

JavaWeb开发(三)3.3——Spring Bean详解(基于XML方式)

一、Bean的概念 由 Spring IoC 容器负责创建、管理所有的Java对象&#xff0c;这些管理的对象称为 Bean&#xff0c;Bean 根据 Spring 配置文件中的信息创建。 二、基于XML方式管理bean对象 eg&#xff1a; <?xml version"1.0" encoding"UTF-8"?&…