前言
使用 GeoTools 将存储在 csv 文件中的数据读出并写入 shapefile 文件,并保存到本地。
GeoTools:是一个开放原代码的 Java 库,提供用于地理空间数据的工具
shapefile 文件:用于描述几何体对象,点、折线与多边形。例如,Shapefile文件可以存储井、河流、湖泊等空间对象的几何位置。除了几何位置,shp文件也可以存储这些空间对象的属性,例如一条河流的名字,一个城市的温度等等。
开发环境
- 操作系统:windows
- 集成开发环境:idea
- 使用编程语言:java
- 构建工具:gradle
开发步骤
-
使用 idea 新建一个空白的 gradle 项目。
- 点击 Create New Project
- 点击 Next ,设置项目名,设置项目所在路径
- 点击 Finish , 等待构建完成,构建时间取决于网速。
- 选中项目 新建代码存放目录。
- 将四个目录全选,然后敲回车,就可以了。
- 当前的项目结构
- 点击 Create New Project
-
在 build.gradle 中引入 GeoTools 依赖
- 在 dependencies 语句块中加入
implementation 'org.geotools:gt-shapefile:23-RC' implementation 'org.geotools:gt-epsg-hsql:23-RC' implementation 'org.geotools:gt-swing:23-RC'
- 在 repositories 语句块中加入
maven { url "https://repo.osgeo.org/repository/release/" }
- 点击更新依赖
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JYXNsbwY-1597714161247)(images/geo-sync.png)] - 完整的 build.gradle 内容
plugins { id 'java' } group 'org.example' version '1.0-SNAPSHOT' repositories { maven { url "https://repo.osgeo.org/repository/release/" } mavenCentral() } dependencies { implementation 'org.geotools:gt-shapefile:23-RC' implementation 'org.geotools:gt-epsg-hsql:23-RC' implementation 'org.geotools:gt-swing:23-RC' testCompile group: 'junit', name: 'junit', version: '4.12' }
- 在 dependencies 语句块中加入
-
创建工具类
package org.example.tutorial; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.UIManager; import org.geotools.data.DataUtilities; import org.geotools.data.DefaultTransaction; import org.geotools.data.Transaction; import org.geotools.data.collection.ListFeatureCollection; import org.geotools.data.shapefile.ShapefileDataStore; import org.geotools.data.shapefile.ShapefileDataStoreFactory; import org.geotools.data.simple.SimpleFeatureCollection; import org.geotools.data.simple.SimpleFeatureSource; import org.geotools.data.simple.SimpleFeatureStore; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; import org.geotools.geometry.jts.JTSFactoryFinder; import org.geotools.referencing.crs.DefaultGeographicCRS; import org.geotools.swing.data.JFileDataStoreChooser; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.GeometryFactory; import org.locationtech.jts.geom.Point; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; /** * This example reads data for point locations and associated attributes from a comma separated text * (CSV) file and exports them as a new shapefile. It illustrates how to build a feature type. * * <p>Note: to keep things simple in the code below the input file should not have additional spaces * or tabs between fields. */ public class Csv2Shape { public static void main(String[] args) throws Exception { // Set cross-platform look & feel for compatability UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); File file = JFileDataStoreChooser.showOpenFile("csv", null); if (file == null) { return; } /* * We use the DataUtilities class to create a FeatureType that will describe the data in our * shapefile. * * See also the createFeatureType method below for another, more flexible approach. */ final SimpleFeatureType TYPE = DataUtilities.createType( "Location", "the_geom:Point:srid=4326," + // <- the geometry attribute: Point type "name:String," + // <- a String attribute "number:Integer" // a number attribute ); System.out.println("TYPE:" + TYPE); /* * A list to collect features as we create them. */ List<SimpleFeature> features = new ArrayList<>(); /* * GeometryFactory will be used to create the geometry attribute of each feature, * using a Point object for the location. */ GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(); SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE); try (BufferedReader reader = new BufferedReader(new FileReader(file))) { /* First line of the data file is the header */ String line = reader.readLine(); System.out.println("Header: " + line); for (line = reader.readLine(); line != null; line = reader.readLine()) { if (line.trim().length() > 0) { // skip blank lines String tokens[] = line.split("\\,"); double latitude = Double.parseDouble(tokens[0]); double longitude = Double.parseDouble(tokens[1]); String name = tokens[2].trim(); int number = Integer.parseInt(tokens[3].trim()); /* Longitude (= x coord) first ! */ Point point = geometryFactory.createPoint(new Coordinate(longitude, latitude)); featureBuilder.add(point); featureBuilder.add(name); featureBuilder.add(number); SimpleFeature feature = featureBuilder.buildFeature(null); features.add(feature); } } } /* * Get an output file name and create the new shapefile */ File newFile = getNewShapeFile(file); ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory(); Map<String, Serializable> params = new HashMap<>(); params.put("url", newFile.toURI().toURL()); params.put("create spatial index", Boolean.TRUE); ShapefileDataStore newDataStore = (ShapefileDataStore) dataStoreFactory.createNewDataStore(params); /* * TYPE is used as a template to describe the file contents */ newDataStore.createSchema(TYPE); /* * Write the features to the shapefile */ Transaction transaction = new DefaultTransaction("create"); String typeName = newDataStore.getTypeNames()[0]; SimpleFeatureSource featureSource = newDataStore.getFeatureSource(typeName); SimpleFeatureType SHAPE_TYPE = featureSource.getSchema(); /* * The Shapefile format has a couple limitations: * - "the_geom" is always first, and used for the geometry attribute name * - "the_geom" must be of type Point, MultiPoint, MuiltiLineString, MultiPolygon * - Attribute names are limited in length * - Not all data types are supported (example Timestamp represented as Date) * * Each data store has different limitations so check the resulting SimpleFeatureType. */ System.out.println("SHAPE:" + SHAPE_TYPE); if (featureSource instanceof SimpleFeatureStore) { SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource; /* * SimpleFeatureStore has a method to add features from a * SimpleFeatureCollection object, so we use the ListFeatureCollection * class to wrap our list of features. */ SimpleFeatureCollection collection = new ListFeatureCollection(TYPE, features); featureStore.setTransaction(transaction); try { featureStore.addFeatures(collection); transaction.commit(); } catch (Exception problem) { problem.printStackTrace(); transaction.rollback(); } finally { transaction.close(); } System.exit(0); // success! } else { System.out.println(typeName + " does not support read/write access"); System.exit(1); } } /** * Prompt the user for the name and path to use for the output shapefile * * @param csvFile the input csv file used to create a default shapefile name * @return name and path for the shapefile as a new File object */ private static File getNewShapeFile(File csvFile) { String path = csvFile.getAbsolutePath(); String newPath = path.substring(0, path.length() - 4) + ".shp"; JFileDataStoreChooser chooser = new JFileDataStoreChooser("shp"); chooser.setDialogTitle("Save shapefile"); chooser.setSelectedFile(new File(newPath)); int returnVal = chooser.showSaveDialog(null); if (returnVal != JFileDataStoreChooser.APPROVE_OPTION) { // the user cancelled the dialog System.exit(0); } File newFile = chooser.getSelectedFile(); if (newFile.equals(csvFile)) { System.out.println("Error: cannot replace " + csvFile); System.exit(0); } return newFile; } }
项目运行结果
将数据读取出来,然后生成 shapefile 文件