使用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.shtmlhtml
本身又仔細研究了一下出錯的地方的源碼,先貼一下在講緣由java
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文件中。git
若是遇到String類型的屬性,會調用 getFieldString(int size,String s)方法,截取掉多餘的字節,下面舉一個真實的例子,size 20,s是"福建省福州市羅源縣",UTF-8編碼轉換爲字節是27,27大於字段長度20,須要截取出前20個字符來。
可是方法內部是用的從末尾刪除的方法,具體看下面圖片。github
你們能夠仔細研究一下代碼,總結一下:
若是是UTF-8編碼,則字段長度必須設計爲value長度的3倍
若是是GBK邊框,則字段長度必須設計爲value長度的2倍
,不然的話若是存儲的中文字段getBytes以後超過字段的length,則會報錯。app
java.lang.StringIndexOutOfBoundsException: String index out of range: 19ide
不知道修改下代碼,強行把多餘的字符寫入到dbf文件中是否會報錯,由於這個原本就是存儲在dbf文件中的,可是是從其餘軟件中導出的,不是用geotools生成的。編碼
若是哪位大神知道,請留言解釋一下。設計
本身想了個解決方案
在調用rest接口以前,把dbf文件重寫一遍,定義字段的時候,字段長度定義爲原來的3倍,這樣geoserver在碰見中文的時候就不會報錯了。rest
貼一下簡單的代碼code
<dependency> <groupId>com.github.albfernandez</groupId> <artifactId>javadbf</artifactId> <version>1.9.2</version> </dependency>
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<DBFField> 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。