1背景
当前Java语言实现的Shapefile读写库中,Geotools中的shapefile插件是使用最多的开源实现,实现比较全面,成熟。但是可能为了与Geotools的核心概念一致,其对小数位DecimalCount的控制支持没有在适配层实现,只是默认了小数位的位数(其底层还是支持小数位的控制的)。
改进有几种方式,其一是参考Shapefile插件自己实现一个独立的干净的Shapefile类库,但是又有不少细节需要考虑;其二是完全实现一套新的Shapefile库,但是意义有多大呢?所以改进的方式就是简单的利用目前Geotools的扩展机制,修改一下适配层,解决一下精确控制小数位的问题。
2解决方法
通过对Shapefile源代码的分析,发现控制DecimalCount的位置有两处:
第一处:org.geotools.data.shapefile.ShapefileDataStore类中createDbaseHeader方法,修改对Number类型的适配,通过AttributeDescriptor的getUserData()数据来获取对decimalCount属性的设定。
修改如下:
else if (Number.class.isAssignableFrom(colType)) { int l = Math.min(fieldLen, 33); int d = Math.max(l - 2, 0); //通过自定义属性支持小数点位数,decimalCount Map<Object, Object> user_data = type.getUserData(); if (user_data != null) { try { d = Integer.parseInt(user_data.getOrDefault("decimalCount", d).toString()); } catch (Exception ex) { // } } header.addColumn(colName, 'N', l, d); } |
第二处:org.geotools.data.shapefile.ShapefileFeatureSource类的readAttributes方法。
其是读取DBF文件,重建AttributeDescriptor,原来的实现没有读取DecimalCount信息,这里加上,同样加入到UserData之中。
实现如下:
int decimalCount=header.getFieldDecimalCount(i); if(decimalCount>0){ build.addUserData("decimalCount", decimalCount); } |
通过修改上诉两处,重新编译Shapefile插件,就可以支持对小数位的精确控制了。
3使用方法
1)引入Shapefile以及依赖的库,这里使用Maven命令可以直接提取依赖库
Shapefile依赖库可以参考上图。
2)在定义属性表的时候使用UserData来存放需要设定的decimalCount信息。
示例如下:
protected SimpleFeatureType createFeatureType() {
SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder(); builder.setName("buildiong"); builder.setCRS(DefaultGeographicCRS.WGS84);
// add attributes in order builder.add("the_geom", Point.class); builder.length(9).add("ID", Integer.class); builder.length(150).add("NAME", String.class); builder.length(10).userData("decimalCount",6).add("X", Double.class); builder.length(10).userData("decimalCount",6).add("Y", Double.class); final SimpleFeatureType BUILDING = builder.buildFeatureType();
return BUILDING; } |
上面例子通过SimpleFeatureTypeBuilder的userData("decimalCount",6)来设定小数位为6位。
4附注,对长度与小数位的理解
DBF使用的是字符串来存储数值类型,其长度的概念是字符数概念,而且所有字段都是定长概念。
如果不够长度,则是先补充小数位(用零补充),然后补充整数位(用空格)补充。
在QGIS里面,显示带小数位的属性表的时候,其长度显示去掉了小数点,就是说会显示长度比我们的定义少一。如我们定义(10,6)在QGIS里面会显示长度为9,小数位为6。
通常我们定义WGS84坐标来讲,若要保留小数点后6位,则定义N(10,6)就可以,因为整数位不会超过三位。
5编译后的插件以及依赖库,可以从下面的链接下载: