geotools:当前fid索引为null,下一个必须在write()之前调用

时间:2018-09-21 09:24:36

标签: java geotools

我想在oracle中导出一个包含空间字段的表作为shp文件。运行导出程序时会发生此错误。我认为保存到shp文件的表中字段的长度会导致此问题。表中字段的最长长度为NVARCHAR2(200)。但是奇怪的是,我手动设置了保存在程序中shp文件中的字段长度信息,但是似乎无效。

这是重要的代码:

public static void doShp(String table) {
    JDBCDataStore jds = null;
    Connection conn = null;
    Transaction tran = new DefaultTransaction();
    String newTable = null;
    try {
        //获取连接
        jds = connOra();
        conn = jds.getConnection(tran);
        newTable = createTempTableOrNotByConfig(table, conn);
        //根据表名获取所有列的结果集
        ResultSet rs = conn.getMetaData().getColumns(null, null, newTable,
                null);
        List<Map<String, Object>> metalist = new ArrayList<Map<String, Object>>();
        //循环将列信息放入List<map>中
        while (rs.next()) {
            String columnName = rs.getString("COLUMN_NAME"); // 列名
            String dataTypeName = rs.getString("TYPE_NAME"); // java.sql.Types类型名称(列类型名称)
            int columnSize = rs.getInt("COLUMN_SIZE"); // 列大小
            int decimalDigits = rs.getInt("DECIMAL_DIGITS"); // 小数位数
            String isNullAble = rs.getString("IS_NULLABLE");
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("columnName", columnName);
            map.put("dataTypeName", dataTypeName);
            map.put("columnSize", columnSize);
            map.put("decimalDigits", decimalDigits);
            map.put("isNullAble", isNullAble);
            metalist.add(map);
        }
        rs.close();
        //根据表名获取主键信息
        ResultSet res1 = conn.getMetaData()
                .getPrimaryKeys(null, null, newTable);
        String columnName = "";
        while (res1.next()) {
            columnName = res1.getString("COLUMN_NAME");
        }
        res1.close();
        Query q = new Query();
        q.setTypeName(newTable);
        //如果有导出的条件,则拼接
        if (cmap.get("filter") != null && !cmap.get("filter").isEmpty()) {
            q.setFilter(CQL.toFilter(cmap.get("filter")));
        }
        // SortBy sb=new SortByImpl("",SortOrder.ASCENDING);
        q.setSortBy(new SortBy[]{SortBy.NATURAL_ORDER});
        //根据query对象获取FeatureReader对象,读取oracle数据,sfs是每行数据的集合体
        FeatureReader<SimpleFeatureType, SimpleFeature> sfs = jds
                .getFeatureReader(q, null);
        //输出文件对象
        File newFile = new File(BASE_PATH + "/map/output/" + newTable + ".shp");
        Map<String, Serializable> params = new HashMap<String, Serializable>();
        params.put("url", (Serializable) newFile.toURI().toURL());
        params.put("create spatial index", (Serializable) Boolean.TRUE);
        ShapefileDataStoreFactory factory = new ShapefileDataStoreFactory();

        //根据params参数获取ShapefileDataStore数据源对象
        ShapefileDataStore dataStore = (ShapefileDataStore) factory
                .createNewDataStore(params);
        //columnName-主键 metalist-列相关信息 table-表名
        SimpleFeatureType type = getType(columnName, metalist, newTable);
        //设置列相关信息-----------------------
        dataStore.createSchema(type);
        //设置编码
        dataStore.setCharset(Charset.forName(cmap.get("charset")));
        //设置事务
        Transaction transaction = new DefaultTransaction("Reproject");
        //获取指定typename和transaction的writer对象(typename为表名)
        String typeName = type.getTypeName();
        FeatureWriter<SimpleFeatureType, SimpleFeature> writer = dataStore.getFeatureWriterAppend(typeName, transaction);
        //获取表中的属性->集合
        List<AttributeDescriptor> list = type.getAttributeDescriptors();
        //获取空间信息字段名
        String the_geom = getGeomCol(newTable, conn);
        // 创建一个事务
        int i = 0;
        try {
            //如果读取不到了就跳出循环
            while (sfs.hasNext()) {
                SimpleFeature feature = sfs.next();


                SimpleFeature copy = writer.next();
                //表中的属性->集合
                for (int j = 0; j < list.size(); j++) {
                    AttributeDescriptor dr = list.get(j);
                    //如果不是空间信息字段
                    if (!dr.getLocalName().equals(the_geom)) {
                        if (isContainChinese(dr.getLocalName())) {
                            //包含中文
                            copy.setAttribute(j, feature.getAttribute(j));
                        } else {
                            copy.setAttribute(dr.getName(), feature.getAttribute(dr.getName()));
                        }
                    }
                }
                Geometry geometry = (Geometry) feature.getDefaultGeometry();
                copy.setDefaultGeometry(geometry);
                writer.write();
                i++;
            }
            tran.commit();
            transaction.commit();
            log.info("导出shp文件成功,共导出数据" + i + "条,请在" + BASE_PATH
                    + "/output/目录下查看结果");
        } catch (Exception problem) {
            log.error(problem);
            transaction.rollback();
            tran.rollback();
            problem.printStackTrace();
        } finally {
            jds.dispose();
            writer.close();
        }
    } catch (Exception e) {
        log.error(e);
        e.printStackTrace();
    } finally {
        if (jds != null)
            jds.dispose();
    }
    updateOutFileName(table.toUpperCase());
    saveTempTableNameToConf(newTable);
}


private static SimpleFeatureType getType(String pkcol, List<Map<String, Object>> list, String newTable) {
    //定义图形信息和属性信息
    SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
    //设置表名
    builder.setName(newTable);
    //根据配置设置二维坐标参考系统
    try {
        crs = CRS.decode("EPSG:" + cmap.get("epsg"));
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    builder.setCRS(crs);
    //循环设置列的列名及其类型(不设置主键)
    for (Map<String, Object> m : list) {
        if (m.get("columnName").toString().equals(pkcol)) {
            continue;
        }
        //获取类型为空间属性类型的列
        if (m.get("dataTypeName").equals("SDO_GEOMETRY")) {
            builder.add(m.get("columnName").toString(), Polygon.class);
        }
        if (m.get("dataTypeName").toString().equals("NUMBER")) {
            //decimalDigits-小数位数
            if (Integer.parseInt(m.get("decimalDigits").toString()) > 0) {
                builder.add(m.get("columnName").toString(), Double.class);
            } else {
                builder.add(m.get("columnName").toString(), Integer.class);
            }

        }
        if (m.get("dataTypeName").toString().equals("FLOAT") || m.get("dataTypeName").toString().equals("DOUBLE")) {
            builder.add(m.get("columnName").toString(), Double.class);
        }
        if (m.get("dataTypeName").toString().equals("VARCHAR2") || m.get("dataTypeName").toString().equals("NVARCHAR2")) {
            builder.length(2 * (Integer.parseInt(m.get("columnSize").toString())))
                    .add(m.get("columnName").toString(), String.class);
        }
        if (m.get("dataTypeName").toString().equals("DATE")) {
            builder.add(m.get("columnName").toString(), Date.class);

        }
    }
    return builder.buildFeatureType();
}

错误:

  

java.io.IOException:当前fid索引为null,下一个必须调用   在write()之前   org.geotools.data.shapefile.fid.IndexedFidWriter.write(IndexedFidWriter.java:243)     在   org.geotools.data.shapefile.IndexedShapefileFeatureWriter.write(IndexedShapefileFeatureWriter.java:97)     在   org.geotools.data.shapefile.ShapefileFeatureWriter.close(ShapefileFeatureWriter.java:244)     在   org.geotools.data.shapefile.IndexedShapefileFeatureWriter.close(IndexedShapefileFeatureWriter.java:103)     在   org.geotools.data.InProcessLockingManager $ 1.close(InProcessLockingManager.java:316)     在   org.geotools.data.store.DiffTransactionState.commit(DiffTransactionState.java:196)     在   org.geotools.data.DefaultTransaction.commit(DefaultTransaction.java:166)     在com.bitservice.map.Ora2shpFile.doShp(Ora2shpFile.java:269)处   com.bitservice.map.Ora2shpFile.main(Ora2shpFile.java:140)由以下原因引起:   java.lang.StringIndexOutOfBoundsException:字符串索引超出范围:   253位于java.lang.StringBuffer.charAt(StringBuffer.java:202)   org.geotools.data.shapefile.dbf.DbaseFileWriter $ FieldFormatter.getFieldString(DbaseFileWriter.java:361)     在   org.geotools.data.shapefile.dbf.DbaseFileWriter.fieldBytes(DbaseFileWriter.java:225)     在   org.geotools.data.shapefile.dbf.DbaseFileWriter.write(DbaseFileWriter.java:196)     在   org.geotools.data.shapefile.ShapefileFeatureWriter.write(ShapefileFeatureWriter.java:439)     在   org.geotools.data.shapefile.IndexedShapefileFeatureWriter.write(IndexedShapefileFeatureWriter.java:98)     在   org.geotools.data.InProcessLockingManager $ 1.write(InProcessLockingManager.java:304)     在   org.geotools.data.store.DiffTransactionState.commit(DiffTransactionState.java:180)     ...还有3个

这是类型信息:

FID INTEGER
THE_GEOM    MDSYS.SDO_GEOMETRY
BSM NUMBER(10)
YSDM    VARCHAR2(10)
ZDDM    VARCHAR2(19)
BDCDYH  VARCHAR2(28)
ZDTZM   VARCHAR2(2)
ZL  VARCHAR2(200)
ZDMJ    NUMBER(15,4)
MJDW    VARCHAR2(2)
YT  VARCHAR2(4)
DJ  VARCHAR2(2)
JG  NUMBER(15,4)
QLLX    VARCHAR2(2)
QLXZ    VARCHAR2(4)
QLSDFS  VARCHAR2(2)
RJL VARCHAR2(200)
JZMD    NUMBER(3,2)
JZXG    NUMBER(5,2)
ZDSZD   NVARCHAR2(200)
ZDSZN   VARCHAR2(200)
ZDSZX   VARCHAR2(200)
ZDSZB   VARCHAR2(200)
ZDT VARCHAR2(200)
TFH VARCHAR2(50)
BZ  VARCHAR2(200)
YTMC    VARCHAR2(200)
QXDM    VARCHAR2(6)

2 个答案:

答案 0 :(得分:0)

我在您的代码中看不到问题,但我怀疑您的数据中有2个字节的汉字,这会使任何属性超出shapefile强制执行的(愚蠢)宽度限制为128个字符。

使用geopackage这样的现代格式可能会更好,GeoTools supports与shapefile相同,但没有限制。

答案 1 :(得分:0)

这些天,当我从“ shp”提取点到新的“ shp”时发现了同样的错误。新文件是“ UTF-8”编码的,因为我总是使用此字符集创建文件。

dataStore.setCharset(Charset.forName("UTF-8"));

经过一番调查,我发现原始文件位于不同的字符集中。 所以我尝试删除setCharset,但异常消失了。

我猜你在字符集上也有类似的问题。