在GeoServer中文社区的讨论地址为:http://opengeo.cn/bbs/read.php?tid=1701&page=e&#a
使用geotools修改shapefile之后, 发现dbf文件内容中, 属性名都成了乱码, 但属性值就不是乱码。修改之前还没有乱码的。
而且在代码中也已经通过以下方式设置过编码方式了:
ShapefileDataStore shape = new ShapefileDataStore(url);
shape.setStringCharset(Charset.forName("GBK"));
我的修改代码如下:
/**
* 修改shapefile.
* @param dataStore
* @param fidStr 要修改的数据对应的featureID
* @return
*/
public static boolean updateShapeFile(ShapefileDataStore dataStore,String fidStr)
{
DefaultTransaction transaction = null;
SimpleFeatureStore store = null;
try {
dataStore.setStringCharset(Charset.forName("GBK"));
String[] featureNames = dataStore.getTypeNames();
String featureName = featureNames[0];
// 创建默认的事务对象
transaction = new DefaultTransaction();
// 同时标明数据源使用的要素名称,通常Shapefile文件名称和Shapefile类型名称通常是一样的。
store = (SimpleFeatureStore) dataStore.getFeatureSource(featureName);
// 关联默认事务和数据源
store.setTransaction(transaction);
//创建过滤器
FilterFactory2 ff = (FilterFactory2) CommonFactoryFinder.getFilterFactory2(null);
Set<FeatureId> fids = new HashSet<FeatureId>();
FeatureId fid = ff.featureId(fidStr);
fids.add(fid);
Filter filter = (Filter) ff.id(fids);
//根据过滤器对过滤的feature进行修改
store.modifyFeatures("资料表编号", "test", filter);
// 提交
transaction.commit();
} catch (IOException e) {
e.printStackTrace();
try {
// 回滚
transaction.rollback();
} catch (IOException e1) {
e1.printStackTrace();
}
return false;
}finally{
if(transaction!=null){
// 关闭
transaction.close();
transaction = null;
}
}
return true;
}
经过定位发现问题出在transaction.commit();
而且shp文件的文件内容中也有汉字,但是没有出现乱码的问题,那么就从dbf文件的文件头着手。
查看geotools的源代码,发现对dbf文件的操作都在org\geotools\data\shapefile\dbf这个包下,其中类DbaseFileWriter实现的是对dbf文件的写操作,包括属性名(head)的写入和属性值(body)的写入,而head的写入在
public DbaseFileWriter(DbaseFileHeader header, WritableByteChannel out, Charset charset)
throws IOException {
//写header
header.writeHeader(out);
。。。。。。
}
而writeHeader方法的定义在DbaseFileHeader这个类中.
原来的代码如下:
// write the field name
for (int j = 0; j < 11; j++) {
if (fields.fieldName.length() > j) {
buffer.put((byte) fields.fieldName.charAt(j));
} else {
buffer.put((byte) 0);
}
}
意思就是,将属性名称以byte形式放到buffer中,一个属性名所占字节数不能超过11个,不足11个的用(byte)0补充。
关键就在(byte) fields.fieldName.charAt(j),对于汉字来说,占用两个字节,而这里从char转化成byte的时候除了问题.
就拿下面这个字符串来说:
String str = "资";
byte[] bytes = str.getBytes();
for(int i=0;i<bytes.length;i++)
System.out.println(bytes);
输出结果应该是:
-41
-54
这里占用两个字节,是对的.
如果按照它里面的方法的话:
char chars = '资';
byte[] bytes = {(byte)chars};
for(int i=0;i<bytes.length;i++)
System.out.println(bytes);
输出结果是:
68
这里明显是不对的.
就按照上面的逻辑,修改原代码如下(我这里只是方法,这段代码应该再优化一下):
int j = 0;
for(int counter=0; j<11&&counter<fields.fieldName.length(); counter++){
char cha = fields.fieldName.charAt(counter);
String str = new String(cha+"");
byte[] bytes = str.getBytes();
for(int k=0;k<bytes.length;k++){
buffer.put(bytes[k]);
j++;
}
}
if(j!=11){
for(int k=0;k<(11-j);k++){
buffer.put((byte) 0);
}
}