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

news2024/11/25 5:35:36

目录

前言

一、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();
	// 遍历featurecollection
	while (itertor.hasNext()) {
		SimpleFeature feature = itertor.next();
		Collection<Property> p = feature.getProperties();
		Iterator<Property> it = p.iterator();
		// 遍历feature的properties
		while (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.coloradmin.cn/o/2224579.html

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

相关文章

【深度学习中的注意力机制10】11种主流注意力机制112个创新研究paper+代码——交叉注意力(Cross-Attention)

【深度学习中的注意力机制10】11种主流注意力机制112个创新研究paper代码——交叉注意力&#xff08;Cross-Attention&#xff09; 【深度学习中的注意力机制10】11种主流注意力机制112个创新研究paper代码——交叉注意力&#xff08;Cross-Attention&#xff09; 文章目录 【…

‌Spring MVC的主要组件有哪些?

前言 SpringMVC的核心组件包括DispatcherServlet、Controller、HandlerMapping、HandlerAdapter、ViewResolver、ModelAndView等&#xff0c;它们协同工作以支持基于MVC架构的Web应用程序开发。这些组件使得开发人员能够以一种声明式和模块化的方式构建Web应用程序&#xff0c…

小程序开发实战:PDF转换为图片工具开发

目录 一、开发思路 1.1 申请微信小程序 1.2 编写后端接口 1.3 后端接口部署 1.4 微信小程序前端页面开发 1.5 运行效果 1.6 小程序部署上线 今天给大家分享小程序开发系列&#xff0c;PDF转换为图片工具的开发实战&#xff0c;感兴趣的朋友可以一起来学习一下&#xff01…

ECharts饼图-基础南丁格尔玫瑰图,附视频讲解与代码下载

引言&#xff1a; 在数据可视化的世界里&#xff0c;ECharts凭借其丰富的图表类型和强大的配置能力&#xff0c;成为了众多开发者的首选。今天&#xff0c;我将带大家一起实现一个饼图图表&#xff0c;通过该图表我们可以直观地展示和分析数据。此外&#xff0c;我还将提供详…

一、在cubemx下RTC配置调试实例测试

一、rtc的时钟有lse提供。 二、选择rtc唤醒与闹钟功能 内部参数介绍 闹钟配置 在配置时间时&#xff0c;注意将时间信息存储起来&#xff0c;防止复位后时间重新配置。 if(HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR0)! 0x55AA)//判断标志位是否配置过&#xff0c;没有则进…

qt EventFilter用途详解

一、概述 EventFilter是QObject类的一个事件过滤器&#xff0c;当使用installEventFilter方法为某个对象安装事件过滤器时&#xff0c;该对象的eventFilter函数就会被调用。通过重写eventFilter方法&#xff0c;开发者可以在事件处理过程中进行拦截和处理&#xff0c;实现对事…

WSL2 Ubuntu22.04编译安装LLVM

前提 这两天因为工作需要&#xff0c;要编译一个Debug版本的llvm。这里对编译安装过程进行一个简单的记录&#xff0c;同时也记录下这个过程中遇到的几个问题。 下载源码并编译 有关llvm编译安装的官方文档在这里。 从git仓库clone llvm的源码。 git clone https://github.c…

FPGA搭建PCIE3.0通信架构简单读写测试,基于XDMA中断模式,提供3套工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐我已有的PCIE方案本博客方案的PCIE2.0版本 3、PCIE基础知识4、工程详细设计方案工程设计原理框图XDMA配置及使用XDMA中断模块数据缓存架构用户逻辑Windows版本XDMA驱动安装Linux版本XDMA驱动安装测试应用程序工程源码架构PCIE上板…

电磁场-Laplace算子与冲激函数的关系

csdn重新打一遍公式太麻烦了。欢迎转到我的知乎账号上查阅原版文章&#xff0c;也可后台私信我发送原版PDF或者markdown。 电磁场-Laplace算子与冲激函数的关系 - 知乎 下面的文章是一张超大的图片。

论1+2+3+4+... = -1/12 的不同算法

我们熟知自然数全加和&#xff0c; 推导过程如下&#xff0c; 这个解法并不难&#xff0c;非常容易看懂&#xff0c;但是并不容易真正理解。正负交错和无穷项计算&#xff0c;只需要保持方程的形态&#xff0c;就可以“预知”结果。但是这到底说的是什么意思&#xff1f;比如和…

C++扑克牌(poker)2024年CSP-J认证第二轮第一题 CCF信息学奥赛C++ 中小学初级组 第二轮真题解析

目录 C扑克牌&#xff08;poker&#xff09; 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、运行结果 五、考点分析 六、推荐资料 C扑克牌&#xff08;poker&#xff09; 2024年CSP-J认证第二轮第一题 一、题目要求 1、编程实现 小 P 从同学…

HarmonyOS 组件样式@Style 、 @Extend、自定义扩展(AttributeModifier、AttributeUpdater)

1. HarmonyOS Style 、 Extend、自定义扩展&#xff08;AttributeModifier、AttributeUpdater&#xff09; Styles装饰器&#xff1a;定义组件重用样式   ;Extend装饰器&#xff1a;定义扩展组件样式   自定义扩展&#xff1a;AttributeModifier、AttributeUpdater 1.1. 区…

HarmonyOS 5.0应用开发——应用打包HAP、HAR、HSP

【高心星出品】 目录 应用打包HAP、HAR、HSPModule类型HAPHAR创建HAR建立依赖HAR共享内容 HSP创建HSP建立依赖同上HSP共享内容同上 HAR VS HSP 应用打包HAP、HAR、HSP 一个应用通常会包含多种功能&#xff0c;将不同的功能特性按模块来划分和管理是一种良好的设计方式。在开发…

【哈工大_操作系统实验】Lab9 proc文件系统的实现

本节将更新哈工大《操作系统》课程第九个 Lab 实验 proc文件系统的实现。按照实验书要求&#xff0c;介绍了非常详细的实验操作流程&#xff0c;并提供了超级无敌详细的代码注释。 实验目的&#xff1a; 掌握虚拟文件系统的实现原理&#xff1b;实践文件、目录、文件系统等概念…

【C++开篇】

首先初阶的数据结构相信大家已经学习的差不多了&#xff0c;关于初阶数据结构排序的相关内容的总结随后我也会给大家分享出来。C语言和C有许多相同的地方&#xff0c;但也有许多不相同的地方。接下来的C部分&#xff0c;我们主要是针对C与C语言不同的地方来与大家进行分享。其中…

量子变分算法 (python qiskit)

背景 变分量子算法是用于观察嘈杂的近期设备上的量子计算效用的有前途的候选混合算法。变分算法的特点是使用经典优化算法迭代更新参数化试验解决方案或“拟设”。这些方法中最重要的是变分量子特征求解器 (VQE)&#xff0c;它旨在求解给定汉密尔顿量的基态&#xff0c;该汉密尔…

这是一篇vue3 的详细教程

Vue 3 详细教程 一、Vue 3 简介 Vue.js 是一款流行的 JavaScript 前端框架&#xff0c;用于构建用户界面。Vue 3 是其最新版本&#xff0c;带来了许多新特性和性能优化&#xff0c;使开发更加高效和灵活。 二、环境搭建 安装 Node.js 前往Node.js 官方网站下载并安装适合你…

WPF+MVVM案例实战(六)- 自定义分页控件实现

文章目录 1、项目准备2、功能实现1、分页控件 DataPager 实现2、分页控件数据模型与查询行为3、数据界面实现 3、运行效果4、源代码获取 1、项目准备 打开项目 Wpf_Examples&#xff0c;新建 PageBarWindow.xaml 界面、PageBarViewModel.cs ,在用户控件库 UserControlLib中创建…

WASM 使用说明23事(RUST实现)

文章目录 1. wasm是什么1.1 chatgpt定义如下:1.2 wasm关键特性&#xff1a; 2. wasm demo2.1 cargo 创建项目2.2 编写code2.3 安装wasm-pack2.4 编译 3.1 html页面引用wasm代码&#xff08;js引用&#xff09;3.2 访问页面4 导入js function4.1 编写lib.rs文件&#xff0c;内容…

UML 总结(基于《标准建模语言UML教程》)

定义 UML 又称为统一建模语言或标准建模语言&#xff0c;是一种标准的图形化建模语言&#xff0c;它是面向对象分析与设计的一种标准表示。尽管UML 本身没有对过程有任何定义&#xff0c;但UML 对任何使用它的方法&#xff08;或过程&#xff09;提出的要求是&#xff1a;支持用…