将 CSV 转换为 Shp 数据

前言

在GIS开发中,经常需要进行数据的转换处理。在之前的文章中讲了如何使用GeoTools读取Shapefile数据,并且展示了将Shapefile数据导入PostGIS空间数据库的多种方式。但是还缺少Shapefile数据转换来源的操作。

本篇教程在之前文章的基础上讲解如何将CSV文件转换为我们熟悉的Shapefile数据。

开发环境

本文使用开发环境如下,仅供参考。

时间:2025年

GeoTools:34-SNAPSHOT

IDE:IDEA2025.1.2

JDK:17

1. 准备CSV文件

CSV(Comma-Separated Values)文件是一种纯文本格式,用于存储表格数据(如电子表格或数据库)。它以结构简单、兼容性广泛而著称,是数据交换中最常用的格式之一。

CSV文本结构:

复制代码
Name,Age,Occupation
Alice,28,Engineer
Bob,32,Designer
Charlie,45,Manager

CSV表格结构:

2. 安装依赖

在之前开发的基础上增加gt-epsg-hsql依赖包。

xml 复制代码
<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-shapefile</artifactId>
    <version>${geotools.version}</version>
</dependency>
<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-epsg-hsql</artifactId>
    <version>${geotools.version}</version>
</dependency>

3. 读取CSV文件

使用showOpenFile方法打开文件选择框,然后使用createType构造要素结构,第一个参数"location"为要素类型,第二个参数为要素属性。the_geom字段表明数据几何类型为Pointsrid表明数据坐标系为4326以及后面的字段名称和对应字段类型。

java 复制代码
// 设置外观
UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());

// 选择文件
File file = JFileDataStoreChooser.showOpenFile("csv",null);
if(file == null ){
    return;
}

// 创建要素类型
final SimpleFeatureType TYPE = DataUtilities.createType(
        "location",
        "the_geom:Point:srid=4326,"+
                "name:String,"+
                "number:Integer"
);

现在可以读取CSV数据并构造Features,使用GeometryFactory来创建几何属性。

ini 复制代码
// 创建要素
List<SimpleFeature> features = new ArrayList<>();
// GeometryFactory 用来为要素创建几何属性
GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null);
SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);

try(BufferedReader reader = new BufferedReader(new FileReader(file))){
    // 读取第一行头部数据
    String line = reader.readLine();
    for(line = reader.readLine(); line != null; line = reader.readLine()){
        if(line.trim().length()>0){
            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());

            // 构造点
            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);
        }
    }
}

4. 创建Shapefile

ShapefileDataStoreFactory创建Shp工厂,在createDataStore参数中将属性"create spatial index"设置为true标明为Shp数据创建空间索引。

ini 复制代码
// 从要素集创建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 dataStore =  (ShapefileDataStore) dataStoreFactory.createDataStore(params);

// TYPE 用作描述文件内容的模板
dataStore.createSchema(TYPE);

通过确认FeatureSource对象实现了FeatureStore方法来检查是否具有读写权限,使用ListFeatureCollection包装FeatureCollection对象。最后使用transaction.comit()一次性安全地写出所有数据。

ini 复制代码
// 输出要素数据到Shapefile
Transaction transaction = new DefaultTransaction("create");
String typeName = dataStore.getTypeNames()[0];

SimpleFeatureSource featureSource = dataStore.getFeatureSource(typeName);
SimpleFeatureType featureType = featureSource.getSchema();

if(featureSource instanceof SimpleFeatureStore){
    SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;
    SimpleFeatureCollection featureCollection = new ListFeatureCollection(featureType,features);
    featureStore.setTransaction(transaction);

    try {
        featureStore.addFeatures(featureCollection);
        transaction.commit();
    }catch (Exception e){
        e.printStackTrace();
        transaction.rollback();
    }finally {
        transaction.close();
    }
    System.exit(0);
}else {
    System.out.println(typeName + "缺少读|写权限!!");
    System.exit(1);
}

5. Shapefile输出位置

使用getNewShapeFile方法选择Shp输出位置。

ini 复制代码
// 提示输出Shapefile
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("保存 ShapeFile");
    chooser.setSelectedFile(new File(newPath));

    int returnVal = chooser.showSaveDialog(null);

    if(returnVal != JFileDataStoreChooser.APPROVE_OPTION){
        System.exit(0);
    }

    File newFile = chooser.getSelectedFile();
    if(newFile.equals(csvFile)){
        System.out.println("Error:不能替换" + csvFile);
        System.exit(0);
    }
    return newFile;
}
相关推荐
编程猪猪侠9 分钟前
Tailwind CSS 自定义工具类与主题配置指南
前端·css
qhd吴飞13 分钟前
mybatis 差异更新法
java·前端·mybatis
YGY Webgis糕手之路35 分钟前
OpenLayers 快速入门(九)Extent 介绍
前端·经验分享·笔记·vue·web
患得患失94937 分钟前
【前端】【vueDevTools】使用 vueDevTools 插件并修改默认打开编辑器
前端·编辑器
ReturnTrue86838 分钟前
Vue路由状态持久化方案,优雅实现记住表单历史搜索记录!
前端·vue.js
UncleKyrie43 分钟前
一个浏览器插件帮你查看Figma设计稿代码图片和转码
前端
遂心_1 小时前
深入解析前后端分离中的 /api 设计:从路由到代理的完整指南
前端·javascript·api
你听得到111 小时前
Flutter - 手搓一个日历组件,集成单日选择、日期范围选择、国际化、农历和节气显示
前端·flutter·架构
风清云淡_A1 小时前
【REACT18.x】CRA+TS+ANTD5.X封装自定义的hooks复用业务功能
前端·react.js
@大迁世界1 小时前
第7章 React性能优化核心
前端·javascript·react.js·性能优化·前端框架