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

关注我,带你一起学GIS ^

前言

在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,2171万
2,Shanghai,121.47,31.23,2487万
3,Guangzhou,113.26,23.12,1868万
4,Shenzhen,114.05,22.55,1756万
5,Tianjin,117.20,39.08,1373万
6,Chongqing,106.50,29.53,3205万
7,Chengdu,104.06,30.67,2094万
8,Wuhan,114.30,30.60,1121万
9,Hangzhou,120.15,30.28,1194万
10,Nanjing,118.78,32.04,931万
11,Xi'an,108.93,34.27,1295万
12,Changsha,112.97,28.20,839万
13,Zhengzhou,113.62,34.75,1260万
14,Harbin,126.63,45.75,1076万
15,Shenyang,123.43,41.80,831万
16,Qingdao,120.38,36.07,1007万
17,Dalian,121.62,38.92,745万
18,Xiamen,118.08,24.48,516万
19,Ningbo,121.55,29.88,854万
20,Hefei,117.28,31.86,937万
21,Fuzhou,119.30,26.08,829万
22,Jinan,117.00,36.67,920万
23,Taiyuan,112.55,37.87,530万
24,Changchun,125.35,43.88,906万
25,Kunming,102.72,25.04,846万
26,Nanning,108.37,22.82,874万
27,Lanzhou,103.82,36.06,435万
28,Yinchuan,106.27,38.47,285万
29,Xining,101.77,36.62,263万
30,Urümqi,87.62,43.82,405万
31,Lhasa,91.11,29.65,86万
32,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开发  相关内容,欢迎关注 

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部