Bootstrap

Java使用GeoTools读写shp文件

根据geotools自己封装的工具类,主要有shp文件的内容读取,转geojson,要素的增删改,新shp生成

需要的依赖

这里主要用的是geotools的依赖,版本是<geotools.version>23.2</geotools.version>
还用到了fastjson,版本1.2.57

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.57</version>
</dependency>
<!-- geotools -->
<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-shapefile</artifactId>
    <version>${geotools.version}</version>
</dependency>
<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-geojson</artifactId>
    <version>${geotools.version}</version>
</dependency>
<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-cql</artifactId>
    <version>${geotools.version}</version>
</dependency>
<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-ysld</artifactId>
    <version>${geotools.version}</version>
</dependency>
<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-epsg-hsql</artifactId>
    <version>${geotools.version}</version>
</dependency>
<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-epsg-extension</artifactId>
    <version>${geotools.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.geotools/gt-main -->
<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-main</artifactId>
    <version>${geotools.version}</version>
</dependency>
<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-opengis</artifactId>
    <version>${geotools.version}</version>
</dependency>
<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-xml</artifactId>
    <version>${geotools.version}</version>
</dependency>
<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-referencing</artifactId>
    <version>${geotools.version}</version>
</dependency>

如果不好下需要指定一下repository

<repository>
    <id>GeoSolutions</id>
    <url>http://maven.geo-solutions.it/</url>
</repository>

读取工具

public class ShapeFileReaderUtils {

    /**
     * 校验shp文件
     *
     * @param fileUrl 文件地址 shp或shp文件夹
     * @return File
     * @throws Exception e
     */
    public static File checkShapeFile(String fileUrl) throws Exception {
        File file = new File(fileUrl);
        if (file.isDirectory()) {
            File[] fa = file.listFiles();
            if (fa == null || fa.length < 1) {
                throw new Exception("找不到shp文件");
            }
            boolean flag = true;
            for (File f : fa) {
                if (new ShpFiles(file).exists(ShpFileType.SHP)) {
                    file = f;
                    flag = false;
                    break;
                }
            }
            if (flag) {
                throw new Exception("找不到shp文件");
            }
        } else {
            if (!new ShpFiles(file).exists(ShpFileType.SHP)) {
                throw new Exception("找不到shp文件");
            }
        }
        return file;
    }

    /**
     * shp文件要素源
     *
     * @param fileUrl 文件地址
     * @return ContentFeatureSource
     * @throws Exception e
     */
    public static ContentFeatureSource getFeatureSourceFromShapeFile(String fileUrl) throws Exception {
        ShapefileDataStore sds = null;
        try {
            ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();
            File file = checkShapeFile(fileUrl);

            sds = (ShapefileDataStore) dataStoreFactory.createDataStore(file.toURI().toURL());
            String type = sds.getTypeNames()[0];
            sds.setCharset(getShapeFileCharsetName(fileUrl));

            return sds.getFeatureSource(type);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            assert sds != null;
            sds.dispose();
        }
    }

    /**
     * 获取要素几何类型
     *
     * @param featureSource 要素源
     * @return 几何类型
     */
    public static String getGeometryTypeName(SimpleFeatureSource featureSource) {
        SimpleFeatureType schema = featureSource.getSchema();
        return schema.getGeometryDescriptor().getType().getName().toString();
    }

    /**
     * shp转geoJsonArray
     *
     * @param fileUrl 文件地址
     * @return JSONArray
     */
    public static JSONArray shapeFileToJsonArray(String fileUrl) throws IOException {
        JSONArray array = new JSONArray();
        FeatureJSON featureJSON = new FeatureJSON();
        FeatureReader<SimpleFeatureType, SimpleFeature> featureReader = null;
        try {
            ContentFeatureSource featureSource = getFeatureSourceFromShapeFile(fileUrl);
            assert featureSource != null;
            featureReader = featureSource.getReader();
            while (featureReader.hasNext()) {
                SimpleFeature feature = featureReader.next();
                StringWriter writer = new StringWriter();
                featureJSON.writeFeature(feature, writer);
                JSONObject json = JSONObject.parseObject(String.valueOf(writer));
                array.add(json);
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (featureReader != null) {
                featureReader.close();
            }
        }

        return array;
    }

    /**
     * shp转geoJsonArray
     *
     * @param fileUrl shp文件地址
     * @param filter  Filter 参考https://docs.geotools.org/latest/userguide/library/main/filter.html
     * @return JSONArray
     */
    public static JSONArray shapeFileToJsonArray(String fileUrl, Filter filter) throws IOException {
        JSONArray array = new JSONArray();
        FeatureJSON featureJSON = new FeatureJSON();
        FeatureReader<SimpleFeatureType, SimpleFeature> featureReader = null;
        try {
            ContentFeatureSource featureSource = getFeatureSourceFromShapeFile(fileUrl);
			assert featureSource != null;
            featureReader = featureSource.getReader(filter);
            while (featureReader.hasNext()) {
                SimpleFeature feature = featureReader.next();
                StringWriter writer = new StringWriter();
                featureJSON.writeFeature(feature, writer);
                JSONObject json = JSONObject.parseObject(String.valueOf(writer));
                array.add(json);
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (featureReader != null) {
                featureReader.close();
            }
        }

        return array;
    }

    /**
     * 获取shp几何对象集合
     *
     * @param fileUrl 文件地址
     * @return 几何集合
     */
    public static List<Geometry> getGeometryList(String fileUrl) throws IOException {
        List<Geometry> geometryList = new ArrayList<>();
        ShapefileReader r = null;
        try {
            r = new ShapefileReader(new ShpFiles(fileUrl), false, false, new GeometryFactory());
            while (r.hasNext()) {
                Geometry shape = (Geometry) r.nextRecord().shape();
                geometryList.add(shape);
            }
        } catch (Exception e) {
            if (r != null) {
                r.close();
            }
            e.printStackTrace();
        }

        return geometryList;
    }

    /**
     * 带过滤器的获取shp几何方法
     * 使用FeatureReader而不是ShapefileReader,效率可能会低一些
     *
     * @param fileUrl shp文件地址
     * @param filter  Filter 参考https://docs.geotools.org/latest/userguide/library/main/filter.html
     * @return List<Geometry>
     */
    public static List<Geometry> getGeometryList(String fileUrl, Filter filter) throws IOException {
        List<Geometry> geometryList = new ArrayList<>();
        FeatureReader<SimpleFeatureType, SimpleFeature> featureReader = null;

        try {
            ContentFeatureSource featureSource = getFeatureSourceFromShapeFile(fileUrl);
            assert featureSource != null;
            featureReader = featureSource.getReader(filter);
			
            //遍历featureCollection
            while (featureReader.hasNext()) {
                SimpleFeature feature = featureReader.next();
                Geometry geom = (Geometry) feature.getDefaultGeometry();
                geometryList.add(geom);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (featureReader != null) {
                featureReader.close();
            }
        }

        return geometryList;
    }

    /**
     * 读取shp属性表
     *
     * @param path dbf路径
     * @return JSONArray
     */
    public static JSONArray getAttributesList(String path) {
        JSONArray array = new JSONArray();
        JSONObject object = null;
        Charset charSet = getShapeFileCharsetName(path);
        // try()的括号中可以写多行声明,每个声明的变量类型都必须是Closeable的子类,用分号隔开,自动close
        try (DbaseFileReader reader = new DbaseFileReader(new ShpFiles(path), false, charSet)) {
            DbaseFileHeader header = reader.getHeader();
            int numFields = header.getNumFields();
            //迭代读取记录
            while (reader.hasNext()) {
                try {
                    Object[] entry = reader.readEntry();
                    object = new JSONObject();
                    for (int i = 0; i < numFields; i++) {
                        String title = header.getFieldName(i);
                        Object value = entry[i];
                        object.put(title, value);
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
                array.add(object);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //关闭
        return array;
    }

    /**
     * shp转geoJsonObject
     *
     * @param fileUrl 文件地址
     * @return JSONObject
     */
    public static JSONObject ShapeFileToGeoJsonObject(String fileUrl) throws IOException {
        JSONObject res = new JSONObject();
        res.put("type", "FeatureCollection");
        res.put("features", shapeFileToJsonArray(fileUrl));
        return res;
    }

    public static JSONObject ShapeFileToGeoJsonObject(String fileUrl, Filter filter) throws IOException {
        JSONObject res = new JSONObject();
        res.put("type", "FeatureCollection");
        res.put("features", shapeFileToJsonArray(fileUrl, filter));
        return res;
    }

    /**
     * 高版本arcgis生成的shp会有一个cpg文件记录编码格式
     *
     * @param path shp路径
     * @return 编码格式
     */
    static Charset getShapeFileCharsetName(String path) {
        path = path.replaceAll(".shp", ".cpg");
        File pFile = new File(path);
        String encode = "GBK";
        if (!pFile.exists() || !pFile.isFile()) {
            return Charset.forName(encode);
        }
        File file = new File(path);

        try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
            String tempString;
            // 一次读入一行,直到读入null为文件结束
            while ((tempString = reader.readLine()) != null) {
                // 显示行号
                if ("UTF-8".equals(tempString.toUpperCase())) {
                    encode = "UTF-8";
                    break;
                }
                break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Charset.forName(encode);
    }

}

写入工具

public class ShapeFileWriterUtils {

    /**
     * 单个过滤器的要素移除
     *
     * @param match Filter 参考https://docs.geotools.org/latest/userguide/library/main/filter.html
     * @param path  shp路径
     * @throws IOException e
     */
    public static void removeFeatures(Filter match, String path) throws Exception {
        ShapefileDataStore shapefileDataStore = getShpDataStore(path);
        String typeName = shapefileDataStore.getTypeNames()[0];
        SimpleFeatureStore dataStore = (SimpleFeatureStore) shapefileDataStore.getFeatureSource(typeName);
        Transaction transaction = new DefaultTransaction("remove");
        dataStore.setTransaction(transaction);
        try {
            dataStore.removeFeatures(match);
            transaction.commit();
        } catch (Exception e) {
            transaction.rollback();
        } finally {
            transaction.close();
        }
    }

    /**
     * 多个过滤器的要素移除 单纯记录下FilterFactory2用法,建议条件自己写成单个的
     *
     * @param match Filter 参考https://docs.geotools.org/latest/userguide/library/main/filter.html
     * @param path  shp路径
     * @throws IOException e
     */
    public static void removeFeatures(List<Filter> match, String path) throws Exception {
        // 多个filter可以这样拼成一个
        FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
        Filter filter = ff.or(match);
        Filter filterAnd = ff.and(match);

        removeFeatures(filter, path);
    }

    /**
     * 修改shp文件要素的属性
     *
     * @param attributeName  属性字段名
     * @param attributeValue 属性值
     * @param filter         查询filter
     * @param path           文件路径
     * @throws IOException e
     */
    public static void modifyFeatures(String[] attributeName, Object[] attributeValue, Filter filter, String path) throws Exception {
        ShapefileDataStore shapefileDataStore = getShpDataStore(path);
        Transaction transaction = new DefaultTransaction("modify");
        String typeName = shapefileDataStore.getTypeNames()[0];
        SimpleFeatureStore dataStore = (SimpleFeatureStore) shapefileDataStore.getFeatureSource(typeName);
        dataStore.setTransaction(transaction);
        try {
            dataStore.modifyFeatures(attributeName, attributeValue, filter);
            transaction.commit();
        } catch (Exception e) {
            e.printStackTrace();
            transaction.rollback();
        } finally {
            transaction.close();
        }
    }

    /**
     * 给现有shp增加要素
     *
     * @param featureCollection SimpleFeatureCollection
     * @param path              shp路径
     * @throws Exception e
     */
    public static void appendFeature(SimpleFeatureCollection featureCollection, String path) throws Exception {
        // 创建输出数据存储
        ShapefileDataStore shpDataStore = getShpDataStore(path);
        SimpleFeatureType inputSchema = featureCollection.getSchema();
        SimpleFeatureType dataStoreSchema = shpDataStore.getSchema();
        if (FeatureTypes.equals(inputSchema, dataStoreSchema)) {
            throw new Exception("error! featureCollection schema not equals to dataStore schema!");
        }

        addFeatureTransaction(shpDataStore, featureCollection);
    }

    /**
     * 生成shp
     *
     * @param featureCollection SimpleFeatureCollection
     * @param path              输出路径 shp结尾
     * @throws IOException e
     */
    public static void buildShp(SimpleFeatureCollection featureCollection, String path) throws Exception {
        // 创建输出数据存储
        ShapefileDataStore newDataStore = getShpDataStore(path);
        SimpleFeatureType type = featureCollection.getSchema();

        // 设置输出数据存储
        newDataStore.createSchema(type);
        // 设置坐标系
        newDataStore.forceSchemaCRS(type.getCoordinateReferenceSystem());

        addFeatureTransaction(newDataStore, featureCollection);
    }

    /**
     * geoJson文件转shp
     *
     * @param geoJson geoJson文件
     * @param path    文件输出地址 .shp结尾
     * @throws IOException e
     */
    public static void geoJSON2Shp(File geoJson, String path) throws Exception {
        InputStream in = new FileInputStream(geoJson);
        geoJSON2Shp(in, path);
    }

    /**
     * geoJson转shp 流式
     *
     * @param input geoJson流
     * @param path  文件输出地址 .shp结尾
     * @throws IOException e
     */
    public static void geoJSON2Shp(InputStream input, String path) throws Exception {

        FeatureJSON fjson = new FeatureJSON(new GeometryJSON(15));

        FeatureIterator<SimpleFeature> jsonIt = fjson.streamFeatureCollection(input);

        if (!jsonIt.hasNext()) {
            throw new IllegalArgumentException(
                    "Cannot create shapefile. GeoJSON stream is empty");
        }

        FeatureWriter<SimpleFeatureType, SimpleFeature> writer = null;

        try {
            // 创建输出数据存储
            ShapefileDataStore shpDataStore = getShpDataStore(path);

            // use feature type of first feature
            SimpleFeature firstFeature = jsonIt.next();
            shpDataStore.createSchema(firstFeature.getFeatureType());

            writer = shpDataStore.getFeatureWriterAppend(
                    shpDataStore.getTypeNames()[0], Transaction.AUTO_COMMIT);

            addFeature(firstFeature, writer);

            while (jsonIt.hasNext()) {
                SimpleFeature feature = jsonIt.next();
                addFeature(feature, writer);
            }
        } finally {
            if (writer != null) {
                writer.close();
            }
        }
    }

    /**
     * 若文件存在,返回该shp;若不存在,创建新dataStore
     *
     * @param path 文件路径
     * @return ShapefileDataStore
     * @throws IOException e
     */
    private static ShapefileDataStore getShpDataStore(String path) throws Exception {
        File newFile = new File(path);
        ShapefileDataStore inputDataStore;
        if (newFile.exists()) {
            inputDataStore = (ShapefileDataStore) DataStoreFinder.getDataStore(
                    Collections.singletonMap("url", newFile.toURI().toURL()));
        } else {
            ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();
            inputDataStore = (ShapefileDataStore) dataStoreFactory.createNewDataStore(
                    Collections.singletonMap("url", newFile.toURI().toURL()));
        }
        inputDataStore.setCharset(getShapeFileCharsetName(path));
        return inputDataStore;
    }

    private static void addFeatureTransaction(ShapefileDataStore dataStore, SimpleFeatureCollection featureCollection) throws IOException {
        Transaction transaction = new DefaultTransaction("create");
        String typeName = dataStore.getTypeNames()[0]; // shp文件名称?
        SimpleFeatureStore featureStore = (SimpleFeatureStore) dataStore.getFeatureSource(typeName);

        // 写入要素
        featureStore.setTransaction(transaction);
        try {
            featureStore.addFeatures(featureCollection);
            transaction.commit();
        } catch (Exception problem) {
            problem.printStackTrace();
            transaction.rollback();
        } finally {
            transaction.close();
        }
    }


    private static void addFeature(SimpleFeature feature, FeatureWriter<SimpleFeatureType, SimpleFeature> writer) throws IOException {

        SimpleFeature toWrite = writer.next();
        for (int i = 0; i < toWrite.getType().getAttributeCount(); i++) {
            String name = toWrite.getType().getDescriptor(i).getLocalName();
            toWrite.setAttribute(name, feature.getAttribute(name));
        }

        // copy over the user data
        if (feature.getUserData().size() > 0) {
            toWrite.getUserData().putAll(feature.getUserData());
        }

        // perform the write
        writer.write();
    }

}

使用示例

当初写的测试类,并没有全用到

public class SHPUtilTest {

    private static SimpleFeatureType createFeatureType() throws FactoryException {

        SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
        // set global state
        builder.setName("Location");
        // 设置坐标系的几种方式
//        builder.setCRS(DefaultGeographicCRS.WGS84); // <- Coordinate reference system
//        builder.setCRS(CRS.decode("EPSG:4326")); // <- Coordinate reference system
        builder.setSRS("EPSG:4326");

        // add attributes in order
        builder.add("the_geom", Point.class);
        builder.length(15).add("Name", String.class); // <- 15 chars width for name field
        builder.length(15).add("number", Integer.class);

        // build the type
        return builder.buildFeatureType();
    }

    public static void write1() {
        try {
            // 定义要素类型
            final SimpleFeatureType TYPE = createFeatureType();
            DefaultFeatureCollection collection = new DefaultFeatureCollection("internal", TYPE);
            GeometryFactory geometryFactory = new GeometryFactory();
            SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);

            // 设置属性
            double latitude = Double.parseDouble("117.123456789");
            double longitude = Double.parseDouble("35.320001");
            String Name = "2050003092";
            String Number = "0";
            // 使用geometryFactory 创建要素
            Point point = geometryFactory.createPoint(new Coordinate(longitude, latitude));
            Object[] obj = {point, Name, Number};
            // 使用SimpleFeatureBuilder创建要素
            SimpleFeature feature = featureBuilder.buildFeature(null, obj);
            collection.add(feature);

            ShapeFileWriterUtils.appendFeature(collection, "D:\\newPoi.shp");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void copy1(String inPath, String outPath) throws Exception {
        File inFile = new File(inPath);
        if (!inFile.exists()) {
            throw new Exception("inFile not exist");
        }
        File outFile = new File(outPath);

// Read
        DataStore inputDataStore = DataStoreFinder.getDataStore(
                Collections.singletonMap("url", inFile.toURI().toURL()));

        String inputTypeName = inputDataStore.getTypeNames()[0];
        SimpleFeatureType inputType = inputDataStore.getSchema(inputTypeName);

        FeatureSource<SimpleFeatureType, SimpleFeature>
                source = inputDataStore.getFeatureSource(inputTypeName);

        FeatureCollection<SimpleFeatureType, SimpleFeature>
                inputFeatureCollection = source.getFeatures();

// Write
        ShapefileDataStoreFactory dataStoreFactory =
                new ShapefileDataStoreFactory();
        ShapefileDataStore newDataStore =
                (ShapefileDataStore) dataStoreFactory.createNewDataStore(
                        Collections.singletonMap("url", outFile.toURI().toURL()));

        newDataStore.createSchema(inputType);
        String typeName = newDataStore.getTypeNames()[0];

        SimpleFeatureStore featureStore =
                (SimpleFeatureStore) newDataStore.getFeatureSource(typeName);

        featureStore.addFeatures(inputFeatureCollection);
    }

    public static void queryFeatures() throws Exception {
        Filter filter = CQL.toFilter("Name = '2050003092'");
        ShapeFileWriterUtils.removeFeatures(filter, "D:\\newPoi.shp");
    }

    public static void modifyTest() throws Exception {
        String path = "D:\\test.shp";
        Filter filter = CQL.toFilter("river_name = ''");
        String[] attrs = new String[]{"river_name", "county_id", "city_id"};
        Object[] values = new Object[]{"无名河", "320503", "320500"};

        ShapeFileWriterUtils.modifyFeatures(attrs, values, filter, path);
    }

    public static void main(String[] args) throws Exception {
        modifyTest();
    }
}
;