将 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;
}
相关推荐
weixin_382395239 小时前
为小工厂量身打造:本地部署的物料管理系统带缺料计算
前端·制造
__zRainy__9 小时前
解决pnpm v10+不自动构建
前端·pnpm·工程化
猫猫不是喵喵.9 小时前
Vue3 Props 属性
前端·javascript·vue.js
醉城夜风~10 小时前
CSS元素显示模式(display)
前端·css
AI大模型-小华11 小时前
Codex 三方充值快速入门指南
java·前端·数据库·chatgpt·ai编程·codex·chatgpt pro
做前端的娜娜子13 小时前
同一链接实现 PC Web 与移动 H5 自适应
前端·掘金·金石计划
小帅不太帅13 小时前
架构没变、规模没变,DeepSeek V4 Flash 正式版凭什么暴涨 47 分?
前端·aigc·deepseek
jarvisuni14 小时前
DeepSeekFlash前端依旧拉垮,而且变慢了很多!
前端·javascript·算法
卷福同学15 小时前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端