World Wind Java开发之六——解析shape文件

来源:互联网 发布:java发起get请求 编辑:程序博客网 时间:2024/06/06 00:39

最近一直忙于导师项目的事情了,几天没更新了,昨天和今天研究了下WWJ解析shp文件的源代码,现在记录下,希望可以帮到更多的人!

上一篇博客:World Wind Java开发之五——读取本地shp文件只讲了如何加载shp文件,没有涉及到shp文件的解析,我们这篇博客紧接上一篇博客,利用WWJ来解析shp文件。首先来看用到的源码包和相关类,如下图所示。解析shp文件主要用到Shapefile(shapefile文件类)、ShapefileRecord(shape文件记录类)、DBaseRecord类以及DBaseField(字段类)


1、读取shapefile文件


由上图可以看出有要实例化一个shapefile对象有六种方法,以其中的两种为例,看下源码:
(1)
/** * Opens a Shapefile from an InputStream, and InputStreams to its optional * resources. * <p/> * The source Shapefile may be accompanied optional streams to an index * resource stream, an attribute resource stream, and a projection resource * stream. If any of these streams are null or cannot be read for any * reason, the Shapefile opens without that information. * <p/> * This throws an exception if the shapefile's coordinate system is * unsupported. *  * @param shpStream *            the shapefile geometry file stream. * @param shxStream *            the index file stream, can be null. * @param dbfStream *            the attribute file stream, can be null. * @param prjStream *            the projection file stream, can be null. * @throws IllegalArgumentException *             if the shapefile geometry stream <code>shpStream</code> is *             null. * @throws WWRuntimeException *             if the shapefile cannot be opened for any reason, or if the *             shapefile's coordinate system is unsupported. */public Shapefile(InputStream shpStream, InputStream shxStream,InputStream dbfStream, InputStream prjStream){this(shpStream, shxStream, dbfStream, prjStream, null);}
输入文件流分别对应着.shp .shx .dbf .prj文件
(2)
/** * Opens an Shapefile from a general source. The source type may be one of * the following: * <ul> * <li>{@link java.io.InputStream}</li> * <li>{@link java.net.URL}</li> * <li>{@link File}</li> * <li>{@link String} containing a valid URL description or a file or * resource name available on the classpath.</li> * </ul> * <p/> * The source Shapefile may be accompanied by an optional index file, * attribute file, and projection file. To be recognized by this Shapefile, * accompanying files must be in the same logical folder as the Shapefile, * have the same filename as the Shapefile, and have suffixes ".shx", * ".dbf", and ".prj" respectively. If any of these files do not exist, or * cannot be read for any reason, the Shapefile opens without that * information. * <p/> * This throws an exception if the shapefile's coordinate system is * unsupported, or if the shapefile's coordinate system is unsupported. *  * @param source *            the source of the shapefile. * @throws IllegalArgumentException *             if the source is null or an empty string. * @throws WWRuntimeException *             if the shapefile cannot be opened for any reason. */public Shapefile(Object source){this(source, null);}
这种方法秩序给出shp文件的路径即可,但是若只有shp文件,缺少shx等文件则无法解析shape文件。
根据以上两种方法来实例化一个shapefile对象,源码如下:
String shpFilePath = "D:\\Users\\wwj_data\\states.shp";String shxFilePath = "D:\\Users\\wwj_data\\states.shx";String dbfFilePath = "D:\\Users\\wwj_data\\states.dbf";String prjFilePath = "D:\\Users\\wwj_data\\states.prj";Shapefile shapefile = new Shapefile(shpFilePath);System.out.println(shapefile.getShapeType());
或者:---------------------------------------------------------------------------------------
String shpFilePath = "D:\\Users\\wwj_data\\states.shp";String shxFilePath = "D:\\Users\\wwj_data\\states.shx";String dbfFilePath = "D:\\Users\\wwj_data\\states.dbf";String prjFilePath = "D:\\Users\\wwj_data\\states.prj";InputStream shpInputStream = new FileInputStream(shpFilePath);InputStream shxInputStream = new FileInputStream(shxFilePath);InputStream dbfInputStream = new FileInputStream(dbfFilePath);InputStream prjInputStream = new FileInputStream(prjFilePath);// 实例化一个shapefile类 Shapefile shapefile = new Shapefile(shpInputStream, shxInputStream, dbfInputStream, prjInputStream);System.out.println(shapefile.getShapeType()); // shape类型

这里需要说明的一点是,一开始的时候我是用的Shapefile(Object source)方法,但是报错:Source is NULL,不知是什么原因;用下面这种方法就可以,这个可以不必太纠结。

2、获取shapefile文件的属性表信息

在shapefile.java文件中可以找到 attributeFile字段,包含shapefile文件的属性信息,但是其权限是protected,只需在原java文件中添加一个方法返回改字段值即可。改完源码,重新导出jar文件覆盖引用即可。
protected DBaseFileattributeFile;
/** *  * @方法名称: getAttributesTable ; * @方法描述:  获取属性表 ; * @参数 :@return  * @返回类型: DBaseFile ; * @创建人:奔跑的鸡丝 ; * @创建时间:2014-12-1 下午12:55:33; * @throws */public DBaseFile getAttributesTable(){return this.attributeFile;}
获取属性表后,首先要获取属性表的基本信息,如:shape文件的类型、字段个数以及记录个数。另外输出所有字段名
// 获取shp属性表DBaseFile dBaseFile = shapefile.getAttributesTable();int fieldCount = dBaseFile.getNumberOfFields(); // 字段数int recordsCount = dBaseFile.getNumberOfRecords(); // 记录数System.out.println("字段数为:" + fieldCount);System.out.println("记录数为:" + recordsCount);System.out.println(shapefile.getShapeType()); // shape类型//获取字段集合DBaseField [] dBaseFields=dBaseFile.getFields();for (int i = 0; i < fieldCount; i++){System.out.println(dBaseFields[i].getName());}
运行结果如下:

在ArcMap下打开shp文件的属性表,对比可知输出的结果是正确的。

3、获取字段值

// 解析shape文件try{while (shapefile.hasNext()){ShapefileRecord record = shapefile.nextRecord(); // 获取一条记录DBaseRecord dBaseRecord = record.getAttributes(); // 获取该记录的属性信息Object[] values = dBaseRecord.getValues().toArray();//获取字段值集合for (int i = 0; i < values.length; i++){System.out.println(values[i].toString());}System.out.println("------------------");}}catch (Exception e){e.printStackTrace();System.out.println("解析shapefile文件出错!");}finally{WWIO.closeStream(shapefile, shpFilePath);WWIO.closeStream(shapefile, shxFilePath);WWIO.closeStream(shapefile, dbfFilePath);WWIO.closeStream(shapefile, prjFilePath);}
思路很简单:shapefile文件—>获取一条记录—>获取记录的属性信息-->获取字段值集合。但是有一个问题:不支持中文字段值
调整后运行结果如下:


ArcMap下的属性表如下图所示:

通过对比,发现字段值虽然都读取了,但是顺序却是乱的。目前还未发现是什么原因,下一篇博客再来解决这个问题字段值与字段不对应的问题。下面给出完整的代码:
/** * @方法名称: shapeFileReader ; * @方法描述: 读取sh文件 ; * @参数 :@throws FileNotFoundException * @返回类型: void ; * @创建人:奔跑的鸡丝 ; * @创建时间:2014-12-1 下午12:50:11; * @throws */private void shapeFileReader() throws FileNotFoundException{String shpFilePath = "D:\\Users\\wwj_data\\states.shp";String shxFilePath = "D:\\Users\\wwj_data\\states.shx";String dbfFilePath = "D:\\Users\\wwj_data\\states.dbf";String prjFilePath = "D:\\Users\\wwj_data\\states.prj";InputStream shpInputStream = new FileInputStream(shpFilePath);InputStream shxInputStream = new FileInputStream(shxFilePath);InputStream dbfInputStream = new FileInputStream(dbfFilePath);InputStream prjInputStream = new FileInputStream(prjFilePath);// 实例化一个shapefile类 Shapefile shapefile = new Shapefile(shpInputStream, shxInputStream, dbfInputStream, prjInputStream);// 获取shp属性表DBaseFile dBaseFile = shapefile.getAttributesTable();int fieldCount = dBaseFile.getNumberOfFields(); // 字段数int recordsCount = dBaseFile.getNumberOfRecords(); // 记录数System.out.println("字段数为:" + fieldCount);System.out.println("记录数为:" + recordsCount);System.out.println(shapefile.getShapeType()); // shape类型//获取字段集合DBaseField [] dBaseFields=dBaseFile.getFields();for (int i = 0; i < fieldCount; i++){System.out.print(dBaseFields[i].getName()+"    ");}System.out.println();// 解析shape文件try{while (shapefile.hasNext()){ShapefileRecord record = shapefile.nextRecord(); // 获取一条记录DBaseRecord dBaseRecord = record.getAttributes(); // 获取该记录的属性信息Object[] values = dBaseRecord.getValues().toArray();//获取字段值集合for (int i = 0; i < values.length; i++){System.out.print(values[i].toString()+"        ");}System.out.println("------------------");}}catch (Exception e){e.printStackTrace();System.out.println("解析shapefile文件出错!");}finally{WWIO.closeStream(shapefile, shpFilePath);WWIO.closeStream(shapefile, shxFilePath);WWIO.closeStream(shapefile, dbfFilePath);WWIO.closeStream(shapefile, prjFilePath);}}

-----------------------------------------------华丽的分割线----------------------------------------------
关于上面提到的获取的字段与字段值不对应的问题解决办法:根据字段名来获取字段值。
while (shapefile.hasNext()){ShapefileRecord record = shapefile.nextRecord(); // 获取一条记录DBaseRecord dBaseRecord = record.getAttributes(); // 获取该记录的属性信息ArrayList<String> fieldArrayList = new ArrayList<String>();for (int i = 0; i < fieldCount; i++){/** * 根据字段名称来获取字段值 */String fieldValue = dBaseRecord.getValue(dBaseFields[i].getName()).toString(); //fieldArrayList.add(fieldValue);System.out.print(fieldValue + "        ");}System.out.println("------------------");}
执行结果如下图所示。








2 0
原创粉丝点击