GeoTools:Feature&Shapefile之CRUD操作

        之前在《GIS开源框架:ArcGIS文件地理数据库(GDB)解析与入库》中,从地理数据库的角度对Feature要素进行了解释,接下来,我们将从GeoTools库的角度,重新认识Feature要素,并通过GeoTools实现Shapefile文件在Feature要素层面的CRUD操作。

目录

Feature要素

FeatureClass要素类

Geometry

DataStore数据源

读取Shapefile文件

添加Feature到Shapefile文件中

修改Shapefile文件中的Feature要素属性

删除Shapefile文件中的Feature要素


Feature要素

        所谓Feature要素,实质上就是在map地图上展示出来的东西。严格意义上讲:Feature要素是对现实世界客观实体的抽象表达。

        但是对于Java开发者而言,最简明的解释就是:一个Feature就是一个对象。像Java对象一样,Feature要素可以用于表达客观实体与现实世界相关的信息。这些信息将被组织成attributes属性,然后被写入field字段中保存。

        有时候,对于两个拥有共性的Feature要素,我们就可以对其进行抽象——转为用一个Class类来描述这一类要素。例如:对于两个机场A、B,我们可以创建一个Airport类来描述其公共属性,但是在Map地图上,我们将创建一个FeatureType来进行表达。

         那么,如何来概括Java和Map地图之间的关系呢?我们可以通过下表进行理解,

FeatureClass要素类

        GeoTools中,通过GeoAPI项目提供了Feature、FeatureType、Attribute接口。通常地,GeoAPI提供了十分严格的接口,而GeoTools提供了对应的class类。

         对于一个Feature要素来讲,仅仅有一些简单属性Attributes(例如:String、Integer、Date等类型的)是十分常见的。为了满足这种需求,GeoTools提供了SimpleFeature子类。

Geometry

        Object对象和Feature要素之间的另一个不同之处是:Feature包含一些位置信息。这些位置信息可以通过Geometry几何图形进行收集,并作为Attribute属性字段保存。

         GeoTools提供了 JTS Topology Suite(JTS)模块来描述Geometry几何图形,基于JTS,可以实现对于任何几何图形数据的高效处理操作。

        以下为使用JTS库,基于Well-Known-Text (WKT)格式创建Point点的示例代码,

    @Test
    public void crateGeometryFromWKT() throws  ParseException {
        GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory( null );
        WKTReader reader = new WKTReader( geometryFactory );
        Point point = (Point) reader.read("POINT (1 1)");
        System.out.println(point);
    }

         以下为直接使用GeometryFactory工厂类创建Point的示例代码,

    @Test
    public void crateGeometryByGeometryFactory() throws  ParseException {
        GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory( null );
        Coordinate coordinate = new Coordinate(1,1);
        Point point = geometryFactory.createPoint(coordinate);
        System.out.println(point);
    }

DataStore数据源

        GeoTools提供了DataStore接口,用于表示一个包含空间数据(spatial data)的File文件、DataBase数据库、Service服务——即:空间数据源。API结构如下所示,

         FeatureSource被用于读取数据源中的Feature要素数据,其子类FeatureStore拥有对数据源的读写权限。

读取Shapefile文件

         例如:读取上图所示的out.shp文件中的要素数据示例代码如下,

@Test
    public void readShapefile() throws IOException {
        String filePath = "C:\\Users\\13241\\Documents\\data\\out.shp";
        File file = new File(filePath);
        DataStore dataStore = new ShapefileDataStore(file.toURI().toURL());//创建ShapefileDataStore实例
        String[] typeNames = dataStore.getTypeNames();//获取数据源中所有可获取的图层名称
        System.out.println(Arrays.toString(typeNames));
        //逐个解析图层数据
        for (int i = 0; i < typeNames.length; i++) {
            String typeName = typeNames[i];
            //获取FeatureSource
            SimpleFeatureSource featureSource = dataStore.getFeatureSource(typeName);
            SimpleFeatureCollection features = featureSource.getFeatures();//获取FeatureSource中的Feature集合
            SimpleFeatureIterator iterator = features.features();//获取集合迭代器
            while (iterator.hasNext()){
                SimpleFeature next = iterator.next();
                SimpleFeatureType featureType = next.getFeatureType();
                List<AttributeDescriptor> attributeDescriptors = featureType.getAttributeDescriptors();
                for (int i1 = 0; i1 < attributeDescriptors.size(); i1++) {
                    Name name = attributeDescriptors.get(i1).getName();
                    System.out.print(name+":"+next.getAttribute(name)+"\t");
                }
                Object defaultGeometry = next.getDefaultGeometry();
                System.out.println();
            }
        }
    }

添加Feature到Shapefile文件中

执行添加操作之前的out.shp

         添加Feature到Shapefile文件中的示例代码如下,

  @Test
    public void addFeaturesToShp() throws SchemaException, IOException {
        //Geometry工厂类
        GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
        /*
         * FeatureType-定义Feature的字段结构
         * TYPE is used as a template to describe the file contents
         */
        final SimpleFeatureType TYPE = DataUtilities.createType(
                "Location",
                "the_geom:Point:srid=4326,"
                        + // <- the geometry attribute: Point type
                        "name:String,"
                        + // <- a String attribute
                        "number:Integer" // a number attribute
        );
        String name = "dsandjkadmskladakndsaldmalkdmaldkas";
        Random random = new Random();
        //创建10个新的Feature要素-[带有属性信息的简单Feature-SimpleFeature]
        List<SimpleFeature> features = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);
            Point point = geometryFactory.createPoint(new Coordinate(120.0+Math.random(),32.0+Math.random()));
            //注意字段添加顺序
            featureBuilder.add(point);
            featureBuilder.add(name.substring(0,random.nextInt(name.length())));
            featureBuilder.add(10+random.nextInt(20));
            SimpleFeature simpleFeature = featureBuilder.buildFeature(null);//创建Feature实例
            features.add(simpleFeature);
        }
        //向shp文件中添加新的Feature要素
        SimpleFeatureCollection collection = new ListFeatureCollection(TYPE,features);
        //获取Shapefile数据源
        String filePath = "C:\\Users\\13241\\Documents\\data\\out.shp";
        File file = new File(filePath);
        DataStore dataStore = new ShapefileDataStore(file.toURI().toURL());//创建ShapefileDataStore实例
        SimpleFeatureSource featureSource = dataStore.getFeatureSource("out");//获取FeatureSource
        if( featureSource instanceof SimpleFeatureStore){
            SimpleFeatureStore store = (SimpleFeatureStore) featureSource; // write access!
            store.addFeatures(collection);
        }
    }

        添加之后,可以看到out.shp文件中共计为25个Feature要素。

执行添加操作之后的out.shp

修改Shapefile文件中的Feature要素属性

        可以看到,上面执行完添加操作之后的out.shp属性表中某些记录的name属性为null。下面,我们执行更新操作,将name=null的记录进行修改——统一将name属性修改为xxx。

        考虑到name属性值可能为null,也可能为空白字符串。因此,先通过Filter过滤器,获取到对应的记录,示例代码如下,

    @Test
    public void modifyFeatureFromShp() throws IOException, CQLException {
        //获取数据源
        String filePath = "C:\\Users\\13241\\Documents\\data\\out.shp";
        File file = new File(filePath);
        DataStore dataStore = new ShapefileDataStore(file.toURI().toURL());//创建ShapefileDataStore实例
        SimpleFeatureSource featureSource = dataStore.getFeatureSource("out");//获取FeatureSource
        if( featureSource instanceof SimpleFeatureStore){
            SimpleFeatureStore store = (SimpleFeatureStore) featureSource; // write access!
//            store.modifyFeatures("name", "xxx", CQL.toFilter("name is null"));
            Filter filter = CQL.toFilter("name = '' OR name IS NULL");
//            Query query = new Query(filter);
            SimpleFeatureCollection features = featureSource.getFeatures(filter);
            SimpleFeatureIterator iterator = features.features();
            System.out.println(features.size());
            while (iterator.hasNext()) {
                SimpleFeature next = iterator.next();
                SimpleFeatureType featureType = next.getFeatureType();
                List<AttributeDescriptor> attributeDescriptors = featureType.getAttributeDescriptors();
                for (int i1 = 0; i1 < attributeDescriptors.size(); i1++) {
                    Name name = attributeDescriptors.get(i1).getName();
                    System.out.print(name + ":" + next.getAttribute(name) + "\t");
                }
                System.out.println();
            }
        }
    }

        获取结果如下,

         接着,我们继续使用同样的Filter过滤器,将目标记录的name字段值改为xxx。示例代码如下,

  //根据条件修改记录
    @Test
    public void modifyFeatureFromShp() throws IOException, CQLException {
        //获取数据源
        String filePath = "C:\\Users\\13241\\Documents\\data\\out.shp";
        File file = new File(filePath);
        DataStore dataStore = new ShapefileDataStore(file.toURI().toURL());//创建ShapefileDataStore实例
        SimpleFeatureSource featureSource = dataStore.getFeatureSource("out");//获取FeatureSource
        if( featureSource instanceof SimpleFeatureStore){
            SimpleFeatureStore store = (SimpleFeatureStore) featureSource; // write access!
//            store.modifyFeatures("name", "xxx", CQL.toFilter("name is null"));
            Filter filter = CQL.toFilter("name = '' OR name IS NULL");
            store.modifyFeatures("name","xxx",filter);
        }
    }

        再次查看属性表,可以看到name为空的记录已经被修改成功,

删除Shapefile文件中的Feature要素

        接下来,我们尝试将name='xxx‘的Feature删除掉,示例代码如下,

    //根据条件删除记录
    @Test
    public void deleteFeatureFromShp() throws IOException, CQLException {
        //获取数据源
        String filePath = "C:\\Users\\13241\\Documents\\data\\out.shp";
        File file = new File(filePath);
        DataStore dataStore = new ShapefileDataStore(file.toURI().toURL());//创建ShapefileDataStore实例
        SimpleFeatureSource featureSource = dataStore.getFeatureSource("out");//获取FeatureSource
        if( featureSource instanceof SimpleFeatureStore){
            SimpleFeatureStore store = (SimpleFeatureStore) featureSource; // write access!
//            store.modifyFeatures("name", "xxx", CQL.toFilter("name is null"));
            Filter filter = CQL.toFilter("name = 'xxx'");
            store.removeFeatures(filter);
        }
    }

        可以看到,我们总的Feature要素数量已经由25变为23,并且目标Feature要素也已经被删除掉。

猜你喜欢

转载自blog.csdn.net/weixin_43524214/article/details/129018816
今日推荐