geoserverrest导入shape文件错误-创新互联

使用rest接口导入shp文件时出错,
java.io.ioexception: current fid index is null, next must be called before write(),
网上找了一下,找到了一篇文章,地址http://www.makaidong.com/%E5%8D%9A%E5%AE%A2%E5%9B%AD%E7%9A%84/14090.shtml

成都创新互联主要从事成都网站制作、网站设计、网页设计、企业做网站、公司建网站等业务。立足成都服务惠来,十载网站建设经验,价格优惠、服务专业,欢迎来电咨询建站服务:18980820575

自己又仔细研究了一下出错的地方的源码,先贴一下在讲原因

org.geotools.data.shapefile.dbf.DbaseFileWriter

public String getFieldString(int size, String s) {
            try {
                buffer.replace(0, size, emptyString);
                buffer.setLength(size);
                // international characters must be accounted for so size != length.
                int maxSize = size;
                if (s != null) {
                    buffer.replace(0, size, s);
                    int currentBytes =
                            s.substring(0, Math.min(size, s.length()))
                                    .getBytes(charset.name())
                                    .length;
                    if (currentBytes > size) {
                        char[] c = new char[1];
                        for (int index = size - 1; currentBytes > size; index--) {
                            c[0] = buffer.charAt(index);
                            String string = new String(c);
                            buffer.deleteCharAt(index);
                            currentBytes -= string.getBytes().length;
                            maxSize--;
                        }
                    } else {
                        if (s.length() < size) {
                            maxSize = size - (currentBytes - s.length());
                            for (int i = s.length(); i < size; i++) {
                                buffer.append(' ');
                            }
                        }
                    }
                }

                buffer.setLength(maxSize);

                return buffer.toString();
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException("This error should never occurr", e);
            }
        }

以下是个人分析,可能有不对的地方,见谅:
主要原因是有中文字符引起的
dbf文件中是按字节存储的,而一个汉字,GBK是2个字节,UTF-8是三个字节,StringBuffer 里的charAt是按字符算的,geoserver rest上传文件的过程,不是直接按字节保存的,而是读取shape的全部内容,包括dbf,然后再写入到一个新的shape文件中。

如果遇到String类型的属性,会调用 getFieldString(int size,String s)方法,截取掉多余的字节,下面举一个真实的例子,size 20,s是"福建省福州市罗源县",UTF-8编码转换为字节是27,27大于字段长度20,需要截取出前20个字符来。
但是方法内部是用的从末尾删除的方法,具体看下面图片。
geoserver rest 导入shape文件错误

大家可以仔细研究一下代码,总结一下:
如果是UTF-8编码,则字段长度必须设计为value长度的3倍
如果是GBK边框,则字段长度必须设计为value长度的2倍
,否则的话如果存储的中文字段getBytes之后超过字段的length,则会报错。

java.lang.StringIndexOutOfBoundsException: String index out of range: 19

不知道修改下代码,强行把多余的字符写入到dbf文件中是否会报错,因为这个本来就是存储在dbf文件中的,但是是从其他软件中导出的,不是用geotools生成的。

如果哪位大神知道,请留言解释一下。

自己想了个解决方案
在调用rest接口之前,把dbf文件重写一遍,定义字段的时候,字段长度定义为原来的3倍,这样geoserver在遇见中文的时候就不会报错了。

贴一下简单的代码


        com.github.albfernandez
        javadbf
        1.9.2
 
public static void changeStringLength(String dbfName, String dbfCharest, String ndbfName,
      String newCharset)
      throws Exception {

    try (DBFReader reader = new DBFReader(
        new FileInputStream(dbfName), Charset.forName(dbfCharest));
        DBFWriter writer = new DBFWriter(new FileOutputStream(ndbfName),
            Charset.forName(newCharset))
    ) {

      int numberOfFields = reader.getFieldCount();

      //改变字符串字段的长度
      List fields = Lists.newArrayList();

      for (int i = 0; i < numberOfFields; i++) {
        DBFField field = reader.getField(i);
        //处理字段字符串字段  乘以3,为了适应UTF8是3个字节的问题
        if (field.getType().equals(DBFDataType.CHARACTER) || field.getType()
            .equals(DBFDataType.VARCHAR)) {
          int maxLength = field.getLength() * 3;
          if (maxLength > field.getType().getMaxSize()) {
            maxLength = field.getType().getMaxSize();
          }
          field.setLength(maxLength);
        }
        fields.add(field);
      }

      //设置新文件的头
     writer.setFields(fields.toArray(new DBFField[fields.size()]));

      Object[] rowObjects;

     while ((rowObjects = reader.nextRecord()) != null) {
       writer.addRecord(rowObjects);
      }

    }

  }

通过以上方案暂时解决了中文字符过长的问题,但是不知道会不会触发其他的bug。

另外有需要云服务器可以了解下创新互联scvps.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。


本文题目:geoserverrest导入shape文件错误-创新互联
本文来源:http://scyanting.com/article/poogo.html