• geotools修改shapefile 属性名乱码问题


    在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文件的操作都在orggeotoolsdatashapefiledbf这个包下,其中类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);
                }
            }



  • 相关阅读:
    good
    C# 调用控制台程序,并获取输出写入文件
    正则基础之——环视(Lookaround)
    C# 正则表达式及常用正则表达式
    c# winform 关于DataGridView的一些操作(很全,绝对够用)
    [bzoj4542][Hnoi2016]大数——同余+莫队
    [bzoj4010][HNOI2015]菜肴制作——拓扑排序
    [bzoj5285][Hnoi2018]寻宝游戏——思维+排序
    NOIP2018游记&&总结
    [bzoj5289][Hnoi2018]排列——贪心+堆
  • 原文地址:https://www.cnblogs.com/tian830937/p/4419786.html
Copyright © 2020-2023  润新知