在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();
	// 遍历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的联合读取有一定的关系。行文仓促,定有许多不足之处,如果不足,还请各位专家朋友在评论区留言批评指出,不慎荣幸。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

创建型模式-----建造者模式

目录 背景&#xff1a; 构建模式UML 代码示例 房子成品&#xff1a; 构建器抽象&#xff1a; 具体构建器&#xff1a; 建筑师&#xff1a; 测试部…

从蚂蚁金服面试题窥探STW机制

背景 在Java虚拟机&#xff08;JVM&#xff09;中&#xff0c;垃圾回收&#xff08;GC&#xff09;是一个至关重要的机制&#xff0c;它负责自动管理内存的分配和释放。然而&#xff0c;垃圾回收过程并非没有代价&#xff0c;其中最为显著的一个影响就是STW&#xff08;Stop-T…

跟着鸟儿学飞行?扑翼机器人的感知秘籍

大家好&#xff01;今天来了解一篇扑翼机器人的研究——《Avian-inspired embodied perception in biohybrid flapping-wing robotics》发表于《Nature Communications》。在广阔天空中&#xff0c;鸟类凭借精妙翅膀结构与敏锐感知自由翱翔&#xff0c;这一直吸引着科学家探索其…

从数据中台到数据飞轮:实现数据驱动的升级之路

从数据中台到数据飞轮&#xff1a;实现数据驱动的升级之路 随着数字化转型的推进&#xff0c;数据已经成为企业最重要的资产之一&#xff0c;企业普遍搭建了数据中台&#xff0c;用于整合、管理和共享数据&#xff1b;然而&#xff0c;近年来&#xff0c;数据中台的风潮逐渐减退…

django(3)jinja2模版的使用

启动模版 安装jinja2 pip install jinja2 配置setting TEMPLATES中添加配置 {BACKEND: django.template.backends.jinja2.Jinja2,DIRS: [os.path.join(BASE_DIR,jinja2)], #模版在项目中的所在位置} template中各项的含义 这个配置项中模版自上而下加载&#xff0c;重名…

工具学习_Cobalt Strike

1. Cobalt Strike 概述 Cobalt Strike 是一款基于 java 的渗透测试神器&#xff0c;常被业界人称为 CS 神器。自 3.0 以后已经不在使用 Metasploit 框架而作为一个独立的平台使用&#xff0c;分为客户端与服务端&#xff0c;服务端是一个&#xff0c;客户端可以有多个&#xf…

表格编辑demo

<el-form :model"form" :rules"status ? rules : {}" ref"form" class"form-container" :inline"true"><el-table :data"tableData"><el-table-column label"计算公式"><templat…

API 接口管理 架构 api接口设计

提供给第三方的业务接口应该如何设计呢&#xff1f;需要从哪些方面考虑&#xff1f;以及如何实现这些方面&#xff1f; 1、标准化 RESTful 2、安全性 1&#xff09;请求token&#xff08;防止接口被第三方调用&#xff09; token作为调用系统的凭证。token可以设置一次有效&…

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

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

Linux初阶——信号

一、预备 1、信号的处理方式 1.1. 默认动作 当收到一个信号时&#xff0c;就执行这个信号的默认动作。 1.2. 忽略 当收到一个信号时&#xff0c;就忽略执行这个信号的默认动作。 1.3. 自定义动作 当收到一个信号时&#xff0c;就执行信号的自定义动作。 2、硬件中断 你…

IT监控对接华三CAS云管平台监控方案

概述 CAS云管平台是新华三集团自主研发的虚拟化和云计算管理平台&#xff0c;它主要面向数据中心&#xff0c;提供虚拟化和云计算管理&#xff0c;在教育行业、网络安全领域、高性能计算业务、企业IT部门等领域被广泛应用。在信创国产化背景下&#xff0c;以CAS、Fusion等为代…

Ajax:表单 模板引擎

Ajax&#xff1a;表单 & 模板引擎 form 表单form 属性 Ajax操控表单事件监听阻止默认行为收集表单数据 模板引擎art-template{{}}语法原文输出条件输出循环输出过滤器 原理 form 表单 在HTML中&#xff0c;可以通过<form>创建一个表单&#xff0c;收集用户信息。而采…

基于centos7.9搭建在线购物网站

mall 搭建数据库配置Java配置jar包 一款模仿天猫的在线购物网站&#xff0c;基于centos7.9搭建 搭建数据库 官网下载软件包后上传 基于centos7.9搭建mysql5.6.42 [rootmysql02 ~]# ls anaconda-ks.cfg init.sh MySQL-5.6.42-1.el7.x86_64.rpm-bundle.tar解压 tar -xf My…

Python 自动化运维:Python基础知识

Python 自动化运维&#xff1a;Python基础知识 目录 &#x1f4ca; Python 基础复习 数据类型、控制结构与常用函数面向对象编程&#xff08;OOP&#xff09;与类的使用函数式编程概念与 lambda 表达式异常处理与日志记录的基本实践 1. &#x1f4ca; Python 基础复习 数据…

【论文阅读】Tabbed Out: Subverting the Android Custom Tab Security Model

论文链接&#xff1a;Tabbed Out: Subverting the Android Custom Tab Security Model | IEEE Conference Publication | IEEE Xplore 总览 “Tabbed Out: Subverting the Android Custom Tab Security Model” 由 Philipp Beer 等人撰写&#xff0c;发表于 2024 年 IEEE Symp…

word技巧:如何禁止复制word文件内容?

在文档管理与协作的复杂环境中&#xff0c;确保文档内容的完整性和安全性至关重要。Microsoft Word作为一款广泛使用的文字处理软件&#xff0c;提供了强大的限制编辑功能&#xff0c;允许用户控制对文档内容的修改权限&#xff0c;有效防止未经授权的更改。本文将深入解析Word…

LabVIEW如何学习数据结构和算法

作为LabVIEW程序员&#xff0c;在学习数据结构和算法时&#xff0c;由于LabVIEW以图形编程为主&#xff0c;与传统编程语言的学习方式有些不同。因此&#xff0c;理解算法思想并将其在LabVIEW中实现是关键。 ​ 1. 夯实编程基础概念 LabVIEW与文本编程语言在实现逻辑上的方式…

Maven项目报错:invalid LOC header (bad signature)

文章目录 Maven项目报错&#xff1a;invalid LOC header (bad signature)1. Maven项目加载或Pom.Xml刷新后仍出现如下错误2. 解决方法 Maven项目报错&#xff1a;invalid LOC header (bad signature) 1. Maven项目加载或Pom.Xml刷新后仍出现如下错误 错误提示&#xff1a; in…

方形件排样优化与订单组批问题探析

方形件排样优化与订单组批问题是计算复杂度很高的组合优化问题&#xff0c;在工业工程中有很广泛的应用背景。为实现个性化定制生产模式&#xff0c;企业会选择订单组批的方式&#xff0c;继而通过排样优化实现批量切割&#xff0c;加工完成后再按照不同客户需求进行分拣&#…

高质量短视频素材平台推荐

在当今短视频内容日益增长的时代&#xff0c;拥有高质量的素材显得尤为重要。以下是一些值得关注的短视频素材平台&#xff0c;它们各具特色&#xff0c;适合不同需求的创作者。 蛙学网 蛙学网专注于提供高质量的短视频素材&#xff0c;适合各种创作需求。虽然该平台需要订阅&a…