一、背景
工作中遇到的需求:已有多个shape文件,需要根据shape中的字段关联添加新的字段,不要改变原有shape的坐标系、投影、编码集等。
二、分析
举例分析:BL.shp文件中Kind字段是分类字段,其对应的中文名称在excel中,需要在BL.shp中新增name字段,把中文名称关联BL.shp中
三、实现思路
- 先把对应的中文excel表格整理成txt文本,存储在4-4.txt中。格式形式:中文名称#kind。注:可以直接读取excel表内容,因为原有的excel表格中内容比较复杂,还有其他信息,所以我单独整理出来。
- 使用程序读取4-4.txt文本,把内容存储成key=val形式
- 使用程序读取BL.shp文件,添加name字段,循环遍历shape属性,根据kind字段获取2中的中文name,并且存储BL.shpe。
四、Python脚本实现
- 安装arcgis10.2软件
- 安装开发工具:pycharm
- 编写python脚本:执行脚本的python版本必须是arcgis中的python,可以在pycharm中配置能。
python的实现方式在这里我就不赘述,主要是介绍使用java的geotools方式实现。
五、GeoTools实现方式
Java第三方库GeoTools可以操作shape文件,落地实现思路:
- 使用GeoTools包操作shape文件
- 前端使用JavaFX框架做简单页面
- 最终打包成exe文件
5.1 引入GeoTools
在pom.xml中引入geotools相关jar包
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<geotools.version>20.3</geotools.version>
</properties>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-shapefile</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-api</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-geojson</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-geometry</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-jts-wrapper</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-main</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-epsg-hsql</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-opengis</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-data</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-referencing</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-swing</artifactId>
<version>${geotools.version}</version>
</dependency>
5.2 读取shape文件
读取shape中属性列表,下边是主要代码:
//源shape文件
ShapefileDataStore shapeDS = (ShapefileDataStore) new ShapefileDataStoreFactory().createDataStore(new File(srcfilepath).toURI().toURL());
// 设置属性
SimpleFeatureSource fs = shapeDS.getFeatureSource(shapeDS.getTypeNames()[0]);
SimpleFeatureType schema = fs.getSchema();
List<AttributeDescriptor> attributeDescriptors = schema.getAttributeDescriptors();
5.3 构建输出shape文件
根据原shape构建新的shape文件,原来shape中投影、编码集、属性字段都一样,只是新增name属性字段,主要代码如下:
FileDataStoreFactorySpi factory = new ShapefileDataStoreFactory();
params.put(ShapefileDataStoreFactory.URLP.key, new File(destfilepath).toURI().toURL());
ShapefileDataStore ds = (ShapefileDataStore) factory.createNewDataStore(params);
ds.setCharset(Charset.forName("GBK"));
// 设置属性
SimpleFeatureSource fs = shapeDS.getFeatureSource(shapeDS.getTypeNames()[0]);
SimpleFeatureType schema = fs.getSchema();
List<AttributeDescriptor> attributeDescriptors = schema.getAttributeDescriptors();
SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
CoordinateReferenceSystem coordinateReferenceSystem = schema.getCoordinateReferenceSystem();
tb.setCRS(coordinateReferenceSystem);
tb.setName(schema.getName());
for (AttributeDescriptor attributeDescriptor : attributeDescriptors) {
String localName = attributeDescriptor.getLocalName();
AttributeType type = attributeDescriptor.getType();
String fieldName = attributeDescriptor.getName().toString();
if (fieldName == "the_geom") {
tb.add("the_geom", schema.getGeometryDescriptor().getType().getBinding());
}else{
int length = (int) ((LiteralExpressionImpl)((IsLessThenOrEqualToImpl)attributeDescriptor.getType().getRestrictions().get(0)).getExpression2()).getValue();
tb.length(length);
tb.add(localName, type.getBinding());
}
}
tb.length(128);
tb.add("NAME", String.class);
ds.createSchema(tb.buildFeatureType());
5.4 写入字段信息
根据kind字段关联出来name信息,存储shape中
//写记录
SimpleFeatureIterator it = fs.getFeatures().features();
//设置writer
FeatureWriter<SimpleFeatureType, SimpleFeature> writer = ds.getFeatureWriter(ds.getTypeNames()[0], Transaction.AUTO_COMMIT);
try {
while (it.hasNext()) {
SimpleFeature f = it.next();
SimpleFeature fNew = writer.next();
List arrList = f.getAttributes();
String kind = (String) f.getAttribute("Kind");
String kindstr = kind.split("\|")[0];
String kindName = dictName.get(kindstr);
arrList.add(kindName);
fNew.setAttributes(arrList);
writer.write();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
it.close();
writer.close();
ds.dispose();
shapeDS.dispose();
}
六、遇到的问题
6.1 中文乱码
问题:最终得到的shape中,属性是中文的乱码
解决:因为geotools读取shape时默认编码为
ISO-8859-1
,需要设置为GBK
,如下设置:
ds.setCharset(Charset.forName("GBK"));
6.2 shape文件过大
问题:在开发过程中,读取原有的shape,保存为新的shape时,新shape文件超级大,例如:原有的shape(所有关联文件)是1G,新shape达到了10G
解决:这是应为在构建新shape时,属性字段没有设置长度,而且所有的属性字段都是String字符串形式,这样默认长度是255,导致文件存储过大。构建时设置字段长度,设置成原有字段的长度,新字段name设置固定长度。
// 原有字段设置
int length = (int) ((LiteralExpressionImpl)((IsLessThenOrEqualToImpl)attributeDescriptor.getType().getRestrictions().get(0)).getExpression2()).getValue();
tb.length(length);
tb.add(localName, type.getBinding());
//新增字段设置
tb.length(128);
tb.add("NAME", String.class);