本文主要参考geotools官网教程:Feature Tutorial — GeoTools 32-SNAPSHOT User Guide
一、Feature定义
所谓Feature要素,实质上就是在map地图上展示出来的东西。严格意义上讲:Feature要素是对现实世界客观实体的抽象表达
但是对于Java开发者而言,最简明的解释就是:一个Feature就是一个对象。像Java对象一样,Feature要素可以用于表达客观实体与现实世界相关的信息。这些信息将被组织成attributes属性,然后被写入field字段中保存。
java概念与geotools概念类比如下:
java | geotools |
Object | Feature |
Class | FeatureType |
Field | Attribute |
Method | Operation |
构建Feature需要首先构建一个FeatureType(类比java创建对象,首先得有对象的类)
构建FeatureType的2种方式
1、通过字符串构建FeatureType
private static SimpleFeatureType createFeatureTypeByStr() throws SchemaException {
//the_geom" 必须是 Point, MultiPoint, MuiltiLineString, MultiPolygon 类型的一种
//the_geom" 始终位于第一位,用于几何体属性名称
return DataUtilities.createType("Location",
"the_geom:Point:srid=4326,name:String,number:Integer");
}
2、通过SimpleFeatureTypeBuilder创建
private static SimpleFeatureType createFeatureType(Class<? extends Geometry> geometryClazz) {
SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
builder.setName("Location");
// 设置坐标参考系
builder.setCRS(DefaultGeographicCRS.WGS84);
// 按顺序添加属性
builder.add("the_geom", geometryClazz);
// 名称字段宽度为15个字符
builder.length(15).add("Name", String.class);
builder.add("number", Integer.class);
//构建 type
return builder.buildFeatureType();
}
二、DataStore(数据存储)
GeoTools提供了DataStore接口,用于表示一个包含空间数据的文件、数据库或服务,即:空间数据源。API结构如下所示:
FeatureSource用于读取数据源中的Feature要素数据,其子类FeatureStore拥有对数据源的读写权限。
判断是否可以在 GeoTools 中写入 File
的方法是使用 instanceof
检查
String typeNames = dataStore.getTypeNames()[0];
SimpleFeatureSource source = store.getfeatureSource( typeName );
if( source instanceof SimpleFeatureStore){
SimpleFeatureStore store = (SimpleFeatureStore) source; // write access!
store.addFeatures( featureCollection );
store.removeFeatures( filter ); // filter is like SQL WHERE
store.modifyFeature( attribute, value, filter );
}
三、csv文件转shp文件
1、csv文件准备
按照官网提供的测试数据将下面的代码复制到一个csv文件中
LAT, LON, CITY, NUMBER
46.066667, 11.116667, Trento, 140
44.9441, -93.0852, St Paul, 125
13.752222, 100.493889, Bangkok, 150
45.420833, -75.69, Ottawa, 200
44.9801, -93.251867, Minneapolis, 350
46.519833, 6.6335, Lausanne, 560
48.428611, -123.365556, Victoria, 721
-33.925278, 18.423889, Cape Town, 550
-33.859972, 151.211111, Sydney, 436
41.383333, 2.183333, Barcelona, 914
39.739167, -104.984722, Denver, 869
52.95, -1.133333, Nottingham, 800
45.52, -122.681944, Portland, 840
37.5667,129.681944,Seoul,473
50.733992,7.099814,Bonn,700,2016
2、pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>geotools</artifactId>
<version>1.0-SNAPSHOT</version>
<name>geotools</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<geotools.version>25-SNAPSHOT</geotools.version>
<maven.deploy.skip>true</maven.deploy.skip>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-shapefile</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-swing</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-epsg-hsql</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>net.sourceforge.javacsv</groupId>
<artifactId>javacsv</artifactId>
<version>2.0</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>osgeo</id>
<name>OSGeo Release Repository</name>
<url>https://repo.osgeo.org/repository/release/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</repository>
<repository>
<id>osgeo-snapshot</id>
<name>OSGeo Snapshot Repository</name>
<url>https://repo.osgeo.org/repository/snapshot/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<inherited>true</inherited>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
3、代码实现
3.1、解析读取csv文件并转换成要素集合
private static List<SimpleFeature> readCsv2Feature(SimpleFeatureType type, File file) throws IOException {
List<SimpleFeature> features = new ArrayList<>();
//通过要素类型构建简单要素构建器
SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(type);
//构建空间要素工厂GeometryFactory。通过这个工厂方法,我们可以创建出点、线、面要素。
//需要注意的是,这个方法只创建创建空间要素,并不会创建属性信息
GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
CsvReader csvReader = new CsvReader(file.getAbsolutePath(), ',', StandardCharsets.UTF_8);
//获取表头
csvReader.readHeaders();
while (csvReader.readRecord()) {
Double latitude = Double.parseDouble(csvReader.get(0));
Double longitude = Double.parseDouble(csvReader.get(1));
String name = csvReader.get(2).trim();
int number = Integer.parseInt(csvReader.get(3).trim());
//通过经纬度创建点地理实体
Point point = geometryFactory.createPoint(new Coordinate(longitude, latitude));
//将点地理实体以及其他属性信息添加到要素构建器中
featureBuilder.add(point);
featureBuilder.add(name);
featureBuilder.add(number);
//通过要素构建器构建要素SimpleFeature
SimpleFeature feature = featureBuilder.buildFeature(null);
features.add(feature);
}
return features;
}
3.2、创建shp文件
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;
}
3.3、要素集合保存shp文件中
public static void main(String[] args) throws Exception {
UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
File file = JFileDataStoreChooser.showOpenFile("csv", null);
if (file == null) {
return;
}
//创建一个FeatureType
SimpleFeatureType type = createFeatureType(Point.class);
//将csv转换为feature集合
List<SimpleFeature> features = readCsv2Feature(type, file);
//通过csv文件名创建一个同名的shp文件
File newFile = getNewShapeFile(file);
//通过dataStoreFactory并结合特定的参数创建ShapefileDataStore。
//这些参数包括url(shp文件地址)以及create spatial index(是否创建空间索引)
//这里我们可以理解为一个没有表结构的表
ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();
Map<String, Serializable> params = new HashMap<>(2);
params.put("url", newFile.toURI().toURL());
params.put("create spatial index", Boolean.TRUE);
ShapefileDataStore newDataStore =
(ShapefileDataStore) dataStoreFactory.createNewDataStore(params);
//通过newDataStore创建约束信息,此时表包含了字段信息(type用作描述文件内容的模板)
newDataStore.createSchema(type);
//考虑到一个shp文件会有数十万的图斑,所以geotools在这里引入了事务机制
Transaction transaction = new DefaultTransaction("create");
String typeName = newDataStore.getTypeNames()[0];
SimpleFeatureSource featureSource = newDataStore.getFeatureSource(typeName);
if (featureSource instanceof SimpleFeatureStore) {
SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;
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);
} else {
System.out.println(typeName + " does not support read/write access");
System.exit(1);
}
}
完整代码文件地址: https://download.csdn.net/download/qq_19800029/89065855