天天看點

java用geotools類庫讀取shapefile

前文再续,书接上一回:​​java读取shapefile且用arcgis for js展示​​

java怎么读取shapefile呢?

shapefile是esri公司最先搞出来的,那么arcgis应该是有相关的类库的吧?好像找不到?我问过搞移动端的同事,arcgis for android确有处理shapefile的类库,处理起来易如反掌。但是,在WEB系统,服务器端从shapefile读出数据,最终是要在前端浏览器中展示,像我们目前在建的项目,就是要用arcgis for js来展示这些数据,而安卓系统类似CS项目,有很大的不同。最大的不同,WEB系统中,数据要以JSON的形式给前端,这样才好处理。arcgis for android,没接触过,心存敬畏,会不会很庞大?有没有用?不清楚,我有点害怕,本能地放弃了。

arcgis for java的SDK应该是arcgis engine吧。有时间要了解下。

在java世界里,处理空间信息,最流行的也许就是用​​GeoTools​​了,一个开源的JAVA处理空间信息类库。

网上例子很多,但大同小异。其实读出shp的数据一点都不难。难就难在,geotools读出来的数据形式,如果转成json的话,是GeoJson,而不是EsriJson,前端想用arcgis for js绘制,很难。所以,读取出来后,要转成EsriJson。如何转换,是另一个课题。现在,先读出来再说。

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.geotools.data.FileDataStore;
import org.geotools.data.FileDataStoreFinder;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.shapefile.dbf.DbaseFileHeader;
import org.geotools.data.shapefile.dbf.DbaseFileReader;
import org.geotools.data.shapefile.files.ShpFiles;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.geojson.feature.FeatureJSON;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.opengis.feature.Property;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.TransformException;

import java.io.*;
import java.nio.charset.Charset;
import java.util.*;

/*
    shapefile操作类
 */
public class ShapefileHelper {

    public static Object read(String path) throws IOException {
        /*
            参数path就是shp文件的完整路径,如:E:\\蟠桃会资源清查\\调查图斑.shp  
            系统会自动检查同一个目录下有没有其他相关文件,有的话会一并读出,
            相关文件的路径无须给出
            .shp 存储地理形状和位置信息
            .dbf 存储属性信息
            .shx 索引文件
            .prj 坐标系
            .cpg 字符编码,如UTF-8
            
            读取出来的结果类型为 List<Map<String, Object>>
         */
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();

        File file = getFile(path);
        if (file == null) {
            return list;
        }

        String charset = getCharSet(path);

        FileDataStore store = FileDataStoreFinder.getDataStore(file);
        ((ShapefileDataStore)store).setCharset(Charset.forName(charset));
        SimpleFeatureSource featureSource = store.getFeatureSource();
        SimpleFeatureCollection collection = featureSource.getFeatures();
        SimpleFeatureIterator features = collection.features();
        while (features.hasNext()) {
            Map<String, Object> item = new HashMap<String, Object>();

            SimpleFeature f = features.next();
            Collection<Property> p = f.getProperties();
            Iterator<Property> it = p.iterator();
            while (it.hasNext()) {
                Property pro = it.next();

                String field = pro.getName().toString();
                field = field.equals("the_geom") ? "wkt" : field;

                String value = pro.getValue().toString();
                item.put(field, value);
            }

            list.add(item);
        }

        return list;
    }
    
    private static File getFile(String path){
        File file = new File(path);
        if (file == null) {
            System.out.println("找不到路径:" + path);
        }
        return file;
    }
    /*
        获取shapefile字符编码
        如果存在.cpg文件,则从中读取,否则默认为UTF-8
     */
    private static String getCharSet(String path){
        String charset = "UTF-8";

        int p = path.lastIndexOf(".");
        String cpg = path.substring(0,p) + ".cpg";
        File file = getFile(cpg);
        if(file != null) {
            RandomAccessFile raf = null;
            try {
                raf = new RandomAccessFile(cpg, "r");
                charset = raf.readLine();
                raf.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return charset;
    }
}      

pom.xml

<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-shapefile</artifactId>
    <version>23.0</version>
</dependency>
<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-geojson</artifactId>
    <version>23.0</version>
</dependency>
<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-epsg-hsql</artifactId>
    <version>23.0</version>
</dependency>      

测试一下

@Test
void readSha() throws IOException {
  List<Map<String, Object>> list = (List<Map<String, Object>>) ShapefileHelper.read("E:\\蟠桃会资源清查\\导出成果20200420093045-2\\导出成果20200420093045\\图斑矢量\\调查图斑.shp");
  Console.print(list.size());
}      

但是,从shapefile里读出内容十分轻松,但这只是第一步,要想在前端的arcgis for js中展示出来,考验才刚刚开始。