GIS 数据转换:将 Txt 转换为 Shp 数据

203 阅读4分钟

前言

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

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

开发环境

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

时间:2025年

GeoTools:34-SNAPSHOT

IDE:IDEA2025.1.2

JDK:17

1. 准备Txt文件

Txt(纯文本文件)是一种最基本的文件格式,仅存储无格式的文本数据,适用于各种场景(如数据交换、日志记录、配置文件等)。

如下是全国省会城市人口Txt 文本结构:

ID,Name,Longitude,Latitude,Population
1,Beijing,116.40,39.90,21712,Shanghai,121.47,31.23,24873,Guangzhou,113.26,23.12,18684,Shenzhen,114.05,22.55,17565,Tianjin,117.20,39.08,13736,Chongqing,106.50,29.53,32057,Chengdu,104.06,30.67,20948,Wuhan,114.30,30.60,11219,Hangzhou,120.15,30.28,119410,Nanjing,118.78,32.04,93111,Xi'an,108.93,34.27,129512,Changsha,112.97,28.20,83913,Zhengzhou,113.62,34.75,126014,Harbin,126.63,45.75,107615,Shenyang,123.43,41.80,83116,Qingdao,120.38,36.07,100717,Dalian,121.62,38.92,74518,Xiamen,118.08,24.48,51619,Ningbo,121.55,29.88,85420,Hefei,117.28,31.86,93721,Fuzhou,119.30,26.08,82922,Jinan,117.00,36.67,92023,Taiyuan,112.55,37.87,53024,Changchun,125.35,43.88,90625,Kunming,102.72,25.04,84626,Nanning,108.37,22.82,87427,Lanzhou,103.82,36.06,43528,Yinchuan,106.27,38.47,28529,Xining,101.77,36.62,26330,Urümqi,87.62,43.82,40531,Lhasa,91.11,29.65,8632,Haikou,110.20,20.05,287

2. 安装依赖

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

<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. 读取Txt文件

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

// 设置外观
UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());

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

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

除了使用DataUtilitiescreateType方法构造要素结构之外,还可以使用SimpleFeatureTypeBuilder构造器。使用SimpleFeatureTypeBuilder可以更灵活的设置要素属性,如坐标系统和字段长度。

// 构造要素结构方法
private static SimpleFeatureType createFeatureType() {

    SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
    builder.setName("Population"); // 类型名称
    builder.setCRS(DefaultGeographicCRS.WGS84); // 坐标系统

    // 按顺序添加要素属性信息
    builder.add("the_geom", Point.class);
    builder.add("id", Integer.class);
    builder.length(15).add("Name", String.class); // 限制字段长度
    builder.add("Population", String.class);

    // 构造类型
    final SimpleFeatureType POPULATION = builder.buildFeatureType();

    return POPULATION;
}

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

// 创建要素
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(",");
                int id = Integer.parseInt(tokens[0].trim());
                String name = tokens[1].trim();
                String population = tokens[4];

                double longitude = Double.parseDouble(tokens[2]);
                double latitude = Double.parseDouble(tokens[3]);

                // 构造点
                Point point = geometryFactory.createPoint(new Coordinate(longitude,latitude));
                // 首先添加Geometry属性
                featureBuilder.add(point);

                featureBuilder.add(id);
                featureBuilder.add(name);
                featureBuilder.add(population);
                SimpleFeature feature = featureBuilder.buildFeature(null);
                features.add(feature);
        }
    }
}

注:使用GeoTools构造GIS数据时有些特殊,在添加要素属性时,一定要先添加几何对象,然后再添加其他属性信息。

// 也就是不能像下面这样先添加id属性,然后才添加point对象。
featureBuilder.add(id);
featureBuilder.add(name);
featureBuilder.add(point);

4. 创建Shapefile

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

// 从要素集创建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);
params.put("charset", "UTF-8"); // 设置编码

ShapefileDataStore dataStore =  (ShapefileDataStore) dataStoreFactory.createDataStore(params);

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

对于中文字段,需要设置字符集,以防出现乱码,此处将"charset"设置为"UTF-8"

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

// 输出要素数据到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输出位置,最后输出的结果就是GIS开发中常用的Shp格式了。

// 提示输出Shapefile
private static File getNewShapeFile(File txtFile){
    String path = txtFile.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(txtFile)){
        System.out.println("Error:不能替换" + txtFile);
        System.exit(0);
    }
    return newFile;
}

OpenLayers示例数据下载,请回复关键字:ol数据

全国信息化工程师-GIS 应用水平考试资料,请回复关键字:GIS考试

【GIS之路】 已经接入了智能助手,欢迎关注,欢迎提问。

欢迎访问我的博客网站-长谈GIShttp://shanhaitalk.com

都看到这了,不要忘记点赞、收藏 + 关注

本号不定时更新有关 GIS开发 相关内容,欢迎关注 !