在GeoTools中的Shapefile属性表读取效率之Shp与Dbf对比

目录

前言

一、POI测试数据简介

1、选用的POI数据

2、关于数据的属性数据 

二、属性数据读取的两种方式实现

1、基于DbaseFileReader的读取

2、基于SimpleFeatureSource的读取

三、实际运行对比

1、内存和CPU占用情况

2、运行耗时情况

四、总结


前言

        众所周知,在空间矢量数据Shapefile中,我们的属性表格数据是保存在Dbf文件当中的。因此,我们在读取Shapefile文件时,如果想读取属性数据。可以的选择至少有两个,第一个是直接读取dbf文件,第二个是读取shp文件。当然,两个的读取是有较大的区别的,主要的区别就在于,在我们的矢量数据中,空间字段Geometry是存放在shp文件中的,同时一个geometry字段对应一条属性记录。在一些场景下,比如我们需要在上传之前,解析Top N的属性表格数据来进行预览,就可以不需要读取Geometry信息。

        因此,针对这两种不同的读取方式。我们来做个对比实验,在读取同样大小和数据量的Shapefile文件时,分别带控制台输出和不带控制台输出两种方式,循环10次来调用同样的读取程序,来对比不同的读取模式在不同的输出模式下,其读取的速度和内存的消耗情况。为大家在实际进行项目开发时,根据不同的情况来选择适合的读取方式做一个参考。

        本文将详细介绍使用Java语言开发,调用GeoTools程序分别读取SHP和DBF两种文件,再对比不同的输出模式,比如一种需要向控制台输出信息,另外一种则直接读取就好。博客首先介绍读取的共同的POI数据的基本情况,包括数据的信息、属性表格的数据详情、总条数等,属性数据是整个对比测试实验的基础。然后根据不同的实验情况输出其内存占用和实现消耗对比。通过以上实验,能让您更加了解如何使用正确的方式去调用GeoTools程序,了解不同的属性表格的解析方式。如果您刚好对这方面有兴趣,不妨来这里看看。

一、POI测试数据简介

        为了测试两种不同的读取方式在不同的输出环境下的性能对比,我们首先准备一份基准数据。因此首先对基础数据的基本情况做个介绍,包括数据的字段信息、总数据量等等。

1、选用的POI数据

        为了让程序的读取占用一定的时间,因此我们需要准备稍微多一点的空间矢量数据。如果数据量太少,不同那种情况,其读取的效率都非常快,很快就读取完了。反之,如果太多,则会占用太多的时间和空间,因此我们采用推测的方法,即采用一定量的数据来预测大规模数据的读取性能。这里,我们选用某城市的餐饮POI数据,在QGIS中可以打开这些数据,如下所示:

2、关于数据的属性数据 

        在了解餐饮POI数据的基本情况之后,我们来看一下属性数据的基本情况。依然在QGIS中进行相应信息的查阅。打开数据的属性信息,先来看一些其参考坐标和总数据量的情况。

        可以看到,其空间参考是采用的EPSG:4490参考(即国家2000坐标系,这是目前比较常用的参考坐标系统)。同时,可以在这里看到要素的数目,即跟属性数据的总条数为:36006,差不多3.6余条。再来看一下它的属性字段,大致如下图所示:

        从上图可以看到,属性表格的字段有10个字段,不包括Geometry字段。由于我们只需要读取属性信息,因此暂时可以忽略Geometry信息,当然在空间信息中,Geometry比一般的属性信息更加重要。 在下面的文章中,主要就是对比读取餐饮POI数据中的3.6W条数据。

二、属性数据读取的两种方式实现

        在Geotools的官方文档中可以了解,想要读取Shapefile的属性数据,不仅可以通过读取Shp的方式,也可以读取DBF。其实,在读取Shp时,已经包含了DBF文件的读取,因为Shp中主要存储的是空间的Geometry信息,而属性表格数据全部都保存在DBF文件中。因此本文首先介绍如何使用Geotools来进行具体的读取。

1、基于DbaseFileReader的读取

        首先我们来介绍如何从dbf文件中直接读取属性信息。闲言少叙,这里直接给大家贴出展示代码。关键代码如下所示:

private long readFromDBF(boolean consoleOut) throws IOException {Long startTime = System.currentTimeMillis();File dbfFile = new File(SHP_FILE);ShpFiles shpFile = new ShpFiles(dbfFile);System.out.println(Charset.defaultCharset().toString());DbaseFileReader dbfReader = new DbaseFileReader(shpFile, true, Charset.defaultCharset());// 读取 DBF 文件的头信息DbaseFileHeader header = dbfReader.getHeader();while (dbfReader.hasNext()) {Row row = dbfReader.readRow();for (int i = 0; i < header.getNumFields(); i++) {if(consoleOut) {System.out.print(row.read(i) + "\t");}else {row.read(i);}}if(consoleOut) {System.out.println("");}}System.out.println("属性字段数:" + header.getNumFields());System.out.println("数据记录数:" + header.getNumRecords());dbfReader.close();Long endTime = System.currentTimeMillis();Long time = endTime - startTime;System.out.println("程序运行耗时:"+ time + "毫秒");return time;
}

         通过代码可以看到,读取dbf的方式主要使用的类是:DbaseFileReader,这个类是专门是用来读取dbf文件的。而属性的字段信息,主要就是存放在DbaseFileHeader中,通过DbaseFileHeader就可获取字段,然后通过dbfReader.readRow();来获取数据,这样就可以循环header的表头来获取所有的数据。

        对dbf文件读取器的感兴趣的朋友,可以到源码中一探究竟。这里不进行深究。 介绍完直接读取dbf文件的形式后,我们来介绍一下读取shp的方式。

2、基于SimpleFeatureSource的读取

         除了直接使用DbaseFileReader的方式来读取属性数据,我们还可以基于SimpleFeatureSource来进行数据的读取。在前面系列文章中,曾经进行了比较详细的介绍,因此这里我们也是直接给出代码。关键代码如下所示:

private long readFromSHP(boolean consoleOut) throws Exception{Long startTime = System.currentTimeMillis();File file = new File(SHP_FILE);if (!file.exists()) {System.out.println("文件不存在");return 0L;}ShapefileDataStore store = new ShapefileDataStore(file.toURI().toURL());store.setCharset(Charset.forName("UTF-8"));// 设置中文字符编码store.getCharset();SimpleFeatureSource featureSource = store.getFeatureSource();// 执行查询SimpleFeatureCollection simpleFeatureCollection = featureSource.getFeatures();SimpleFeatureIterator itertor = simpleFeatureCollection.features();// 遍历featurecollectionwhile (itertor.hasNext()) {SimpleFeature feature = itertor.next();Collection<Property> p = feature.getProperties();Iterator<Property> it = p.iterator();// 遍历feature的propertieswhile (it.hasNext()) {Property pro = it.next();if (null != pro && null != pro.getValue()) {String field = pro.getName().toString();String value = pro.getValue().toString();if(consoleOut) {System.out.println(field + "===" + value);}}}if(consoleOut) {System.out.println("------------------------------------------------------");}}Long endTime = System.currentTimeMillis();Long time = endTime - startTime;System.out.println("程序运行耗时:"+ time + "毫秒");return time;
}

        与直接从DBF文件中直接读取类似,为了测试向控制台输出是否会影响效率和内存占用,因此我们在方法中增加日志输出的开关,通过开关来控制相应的输出。

        这里就给出了两种不同的实现方式的属性表格信息读取的关键代码。大家可以直接采用。前提是大家正确的配置了GeoTools的依赖。下面就进行实际例子的运行,同时综合对比指标来看一下实际的运行情况。

三、实际运行对比

        这里,我们将采用循环10次调用的方式,分别给出10次调用的耗时对比。同时使用Java VisualVM来进行运行内存的监控。通过对比实验来观察运行的一些资源消耗。实验分别从以下几个方面进行,对比不同运行模式的内存、CPU占比;对比不同运行模式的读取耗时。其测试代码如下所示:

        首先是是DBF读取模式的测试代码,如下所示:

@Test
public void readFromDbf() throws Exception {Long [] time1 = new Long[DEFAULT_SIZE];for(int i = 0;i < DEFAULT_SIZE;i++) {time1[i] = readFromDBF(true);Thread.sleep(5000);//线程休眠5秒钟}System.out.println("*******************************************");for (Long time : time1) {System.out.print(time+ "\t");}Long [] time2 = new Long[DEFAULT_SIZE];for(int i = 0;i < DEFAULT_SIZE;i++) {time2[i] = readFromDBF(false);Thread.sleep(5000);//线程休眠5秒钟}System.out.println("*******************************************");for (Long time : time2) {System.out.print(time+ "\t");}
}

        同样的,直接读取shp的方式测试代码如下:

 

@Test
public void readFromShp() throws Exception{Long [] time1 = new Long[DEFAULT_SIZE];for(int i = 0;i < DEFAULT_SIZE;i++) {time1[i] = readFromSHP(true);Thread.sleep(5000);//线程休眠5秒钟}System.out.println("*******************************************");System.out.println(time1);for (Long time : time1) {System.out.print(time+ "\t");}Long [] time2 = new Long[DEFAULT_SIZE];for(int i = 0;i < DEFAULT_SIZE;i++) {time2[i] = readFromSHP(false);Thread.sleep(5000);//线程休眠5秒钟}System.out.println("*******************************************");for (Long time : time2) {System.out.print(time+ "\t");}
}

1、内存和CPU占用情况

        首先来看下不同的运行模式的内存和CPU占用情况,这里采用的监控程序使用Java VisualVM(这是jdk自带的监控工具,可以同时监控CPU和内存)。

使用控制台输出的dbf读取资源占用情况图 

不使用控制台输出的dbf读取资源占用情况图  

使用控制台输出的shp读取资源占用情况图  

不使用控制台输出的shp读取资源占用情况图

        提供过以上的图表可以看到, 从CPU的占用来看,不带控制台输出的比带了控制台输出的的占用高。从内存的占用来看,最高占用基本两种方式都差不多。但是从稳定来看,带控制台输出的占比持续时间长一点。

2、运行耗时情况

        与CPU和内存情况相比,程序的运行耗时也是非常重要的一个指标。在之前的代码中,我们分别循环10次来进行程序的调用,然后取消耗的时间来做对比实验。

        采用dbf读取的方式的运行耗时如下:

开启输出 : 
3428, 2625, 2447, 2382, 2445, 2377, 2449, 2254, 2460, 2719禁用输出 : 
1225, 254, 240, 238, 215, 248, 239, 215, 215, 213

        将上述数据做成echarts图表如下所示:

        通过图表的方式很明显的看出,禁用输出后,程序的执行时间有大幅的下降最快只要213毫秒就执行完成。 下面再来看一下shp的读取方式耗时情况。

        采用shp读取的运行耗时情况如下:

开启输出 : 
12131, 6508, 6104, 5849, 5442, 5702, 5250, 5569, 5211, 5030禁用输出 : 
3766, 1082, 707, 839, 789, 736, 711, 720, 730, 685

        将上述数据做成echarts图表如下所示:

        使用shp的读取方式,同样是禁用了输出的耗时更短。而对比dbf和shp两种读取方式,开启输出和禁用输出的耗时几乎是10倍。而两种不同的读取方式,耗差别两到三倍。

四、总结

        以上就是本文的主要内容, 本文将详细介绍使用Java语言开发,调用GeoTools程序分别读取SHP和DBF两种文件,再对比不同的输出模式,比如一种需要向控制台输出信息,另外一种则直接读取就好。博客首先介绍读取的共同的POI数据的基本情况,包括数据的信息、属性表格的数据详情、总条数等,属性数据是整个对比测试实验的基础。然后根据不同的实验情况输出其内存占用和实现消耗对比。通过以上实验,能让您更加了解如何使用正确的方式去调用GeoTools程序,了解不同的属性表格的解析方式。如果您刚好对这方面有兴趣,不妨来这里看看。

        通过上面的对比实验,可以看到。在读取相同数量的数据和机器配置下。读取数据时不开启控制台输出,其性能更高,不仅耗时更短,同时CPU和内存的占比更低。如果不是必须在程序中要读取Geometry数据,建议使用dbf读取属性列表的信息方式,其效率更高,也许与geometry的联合读取有一定的关系。行文仓促,定有许多不足之处,如果不足,还请各位专家朋友在评论区留言批评指出,不慎荣幸。

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

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

相关文章

【C++/Qt 高精度计算qreal temp = static_cast<qreal>(nwidth) / nImgWidth;】

这行代码是C中使用Qt框架时的一个类型转换示例。下面是对这行代码的详细解释&#xff1a; 代码解释 qreal temp1 static_cast<qreal>(nwidth) / nImgWidth;qreal: qreal是Qt框架中定义的一个类型&#xff0c;通常用于表示浮点数。它实际上是float或double的别名&#…

github上传文件代码以及其它github代码

echo "# booksystem2" >> README.md git init git add README.md(此段省略) $ git add . //加的 git commit -m "first commit" git branch -M main git remote add origin gitgithub.com:yuyyyyyydek/booksystem2.git git push -u origin main …

MoonBit 双周报 Vol.58:原生后端支持、多行字符串插值、json.inspect 功能等多项关键特性取得显著进展!

MoonBit支持native后端 Wasm-gc 后端支持 Js-string-builtins proposal 当通过编译选项 -use-js-builtin-string 开启使用 Js-string-builtins 之后&#xff0c;Moonbit 面向 wasm-gc 后端时&#xff0c;会使用 JavaScript 中的字符串类型表示 MoonBit 中的字符串&#xff0…

Unity3D 开发技巧

视频教程&#xff1a; Unity3D 开发技巧分享&#xff0c;你可能不知道的小知识 Unity中文课堂教程地址&#xff1a; Unity3D开发-你可能不知道的知识 | Unity 中文课堂 Start 函数可以用协程 默认协同函数 Start 可将 void 改为IEnumerator 作为协程启动 using System.Colle…

多层感知机的从零实现与softmax的从零实现(真·0000零基础)

今天再读zh.d2l书&#xff08;4.2. 多层感知机的从零开始实现 — 动手学深度学习 2.0.0 documentation&#xff09;&#xff0c; 看了关于多层感知机的从零实现与softmax的从零实现 目录 mlp从零实现&#xff0c; 点击“paddle”的代码 点击“torch”的代码 训练 参数解…

网络爬虫-Python网络爬虫和C#网络爬虫

爬虫是一种从互联网抓取数据信息的自动化程序&#xff0c;通过 HTTP 协议向网站发送请求&#xff0c;获取网页内容&#xff0c;并通过分析网页内容来抓取和存储网页数据。爬虫可以在抓取过程中进行各种异常处理、错误重试等操作&#xff0c;确保爬取持续高效地运行 1、Python网…

DataSophon集成ApacheImpala的过程

注意: 本次安装操作系统环境为Anolis8.9(Centos7和Centos8应该也一样) DataSophon版本为DDP-1.2.1 整合的安装包我放网盘了: 通过网盘分享的文件&#xff1a;impala-4.4.1.tar.gz等2个文件 链接: https://pan.baidu.com/s/18KfkO_BEFa5gVcc16I-Yew?pwdza4k 提取码: za4k 1…

C#与C++交互开发系列(十二):托管和非托管内存管理策略

前言 在进行C#与C互操作开发时&#xff0c;内存管理是一个非常重要的环节。由于C#采用托管内存管理&#xff08;由垃圾回收机制GC控制&#xff09;&#xff0c;而C则使用手动内存管理&#xff08;需要开发者负责分配和释放内存&#xff09;&#xff0c;因此跨语言调用时&#…

光耦的应用

什么是光耦 光耦是一种实现信号隔离的元器件&#xff0c;通常用于各部分电路之间&#xff0c;使其不互相受到影响。 工作原理 光耦是由一个发光二极管和一个光敏三极管封装而成的。其使用原理为&#xff1a; 当发光二极管有信号输入时&#xff0c;则会被点亮&#xff0c;此时…

PHP-FPM 性能配置优化

4 核 8 G 服务器大约可以开启 500 个 PHP-FPM&#xff0c;极限吞吐量在 580 qps &#xff08;Query Per Second 每秒查询数&#xff09;左右。 Nginx php-fpm 是怎么工作的&#xff1f; php-fpm 全称是 PHP FastCGI Process Manager 的简称&#xff0c;从名字可得知&#xff…

OJ在线编程常见输入输出(java版本)

基础知识 BufferedReader 概述 BufferedReader是Java I/O中的一个类&#xff0c;它是一个带缓冲区的字符输入流&#xff0c;用于从字符输入流中读取字符。它提供了一种逐行读取文本文件的方法&#xff0c;可以轻松地读取大量文本数据&#xff0c;并且可以通过使用缓冲区来提…

基于SSM的“众优”大学生家教平台的设计与实现

前言 对于当今社会的人们来说&#xff0c;互联网技术是必不可少的&#xff0c;随着经济和技术的不断发展&#xff0c;计算机已经深入到各个领域。“众优”大学生家教平台将人们的时间需求与计算机技术结合起来&#xff0c;架起一座桥梁&#xff0c;使用在线查看“众优”大学生…

设计模式讲解

设计原则 单一职责原则 > 一个对象应该只包含单一的职责&#xff0c;并且该职责被完整地封装在一个类中 > //一个人类 public class People {/*** 人类会编程*/public void coding(){System.out.println("int mian() {");System.out.println(" print…

CI/CD 流水线系统-开源框架Tekton

文章目录 CI/CD 流水线系统-开源框架Tekton什么是TektonTekton优点Tekton 组件介绍Tekton 概念术语 CI/CD 流水线系统-开源框架Tekton 什么是Tekton 官网&#xff1a;https://tekton.dev/ Tekton 是一个强大、灵活的构建 CI/CD 流水线系统的开源框架,允许开发者构建、测试和…

【牛客算法】某司面试算法题:循环右移二叉树

一、算法题描述 1.1 算法描述 现有一棵n个节点构成的二叉树&#xff0c;请你将每一层的节点向右循环位移k位。某层向右位移一位(即k1)的含义为&#xff1a; 若当前节点为左孩子节点&#xff0c;会变成当前节点的双亲节点的右孩子节点。 若当前节点为右儿子&#xff0c;会变成…

直播系统源码技术搭建部署流程及配置步骤

系统环境要求 PHP版本&#xff1a;5.6、7.3 Mysql版本&#xff1a;5.6&#xff0c;5.7需要关闭严格模式 Nginx&#xff1a;任何版本 Redis&#xff1a;需要给所有PHP版本安装Redis扩展&#xff0c;不需要设置Redis密码 最好使用面板安装&#xff1a;宝塔面板 - 简单好用的…

springboot中redis并发锁的等待时间设置长短

问题&#xff1a;等待时间我设置的大一点&#xff0c;还是立刻抛出错误不等待&#xff1b;个人是觉得要立刻抛出错误&#xff0c;首先如果同一把锁并发量太大&#xff0c;没有限流&#xff0c;会造成服务器连接数立刻达到最大连接数&#xff0c;服务不可用&#xff1b;其次等待…

Android——事件冲突处理

当我们给列表的item设置了点击事件后&#xff0c;又给item中的按钮设置了点击事件&#xff0c;此时item的点击事件会失效。 解决 给item的布局xml中设置以下属性 android:descendantFocusability"blocksDescendants"<LinearLayout xmlns:android"http://sc…

HT7181 16.8V,14A高效升压转换器

1、特征 输入电压范围:2.7V-16V 输出电压范围:最高16.8V 固定开关频率:360kHz 可编程峰值电流:14A 高转换效率: 94% (VIN 7.2V, VOUT9.3V, IOUT1.5A) 90% (VIN 7.2V, VOUT9.3V, IOUT 7A) 93% (VIN 7.2V, VOUT12V, IOUT 1.5A) 90% (VIN 7.2V, VOUT12V, IOUT 5.5A) 90% (VIN …

电脑磁盘再次分区

如何把c盘变成一个大的盘&#xff1f; 给电脑的C盘扩容通常涉及到调整硬盘分区的大小&#xff0c;这可以通过多种方法实现&#xff0c;以下是一些常见的步骤&#xff1a; 1. **使用磁盘管理工具**&#xff1a; - 在Windows系统中&#xff0c;可以使用内置的磁盘管理工具来调整…