^ 关注我,带你一起学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
字段表明数据几何类型为Point
;srid
表明数据坐标系为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"
);
除了使用DataUtilities
类createType
方法构造要素结构之外,还可以使用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之路公众号已经接入了智能助手,欢迎大家前来提问。
欢迎访问我的博客网站-长谈GIS:
http://shanhaitalk.com
都看到这了,不要忘记点赞、收藏+关注 哦!
本号不定时更新有关 GIS开发 相关内容,欢迎关注