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

http://blog.csdn.net/giser_whu/article/details/41647117

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

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

1、读取shapefile文件

由上图可以看出有要实例化一个shapefile对象有六种方法,以其中的两种为例,看下源码:
(1)
[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. /** 
  2.      * Opens a Shapefile from an InputStream, and InputStreams to its optional 
  3.      * resources. 
  4.      * <p/> 
  5.      * The source Shapefile may be accompanied optional streams to an index 
  6.      * resource stream, an attribute resource stream, and a projection resource 
  7.      * stream. If any of these streams are null or cannot be read for any 
  8.      * reason, the Shapefile opens without that information. 
  9.      * <p/> 
  10.      * This throws an exception if the shapefile's coordinate system is 
  11.      * unsupported. 
  12.      *  
  13.      * @param shpStream 
  14.      *            the shapefile geometry file stream. 
  15.      * @param shxStream 
  16.      *            the index file stream, can be null. 
  17.      * @param dbfStream 
  18.      *            the attribute file stream, can be null. 
  19.      * @param prjStream 
  20.      *            the projection file stream, can be null. 
  21.      * @throws IllegalArgumentException 
  22.      *             if the shapefile geometry stream <code>shpStream</code> is 
  23.      *             null. 
  24.      * @throws WWRuntimeException 
  25.      *             if the shapefile cannot be opened for any reason, or if the 
  26.      *             shapefile's coordinate system is unsupported. 
  27.      */  
  28.     public Shapefile(InputStream shpStream, InputStream shxStream,  
  29.             InputStream dbfStream, InputStream prjStream)  
  30.     {  
  31.         this(shpStream, shxStream, dbfStream, prjStream, null);  
  32.     }  
输入文件流分别对应着.shp .shx .dbf .prj文件
(2)
[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. /** 
  2.      * Opens an Shapefile from a general source. The source type may be one of 
  3.      * the following: 
  4.      * <ul> 
  5.      * <li>{@link java.io.InputStream}</li> 
  6.      * <li>{@link java.net.URL}</li> 
  7.      * <li>{@link File}</li> 
  8.      * <li>{@link String} containing a valid URL description or a file or 
  9.      * resource name available on the classpath.</li> 
  10.      * </ul> 
  11.      * <p/> 
  12.      * The source Shapefile may be accompanied by an optional index file, 
  13.      * attribute file, and projection file. To be recognized by this Shapefile, 
  14.      * accompanying files must be in the same logical folder as the Shapefile, 
  15.      * have the same filename as the Shapefile, and have suffixes ".shx", 
  16.      * ".dbf", and ".prj" respectively. If any of these files do not exist, or 
  17.      * cannot be read for any reason, the Shapefile opens without that 
  18.      * information. 
  19.      * <p/> 
  20.      * This throws an exception if the shapefile's coordinate system is 
  21.      * unsupported, or if the shapefile's coordinate system is unsupported. 
  22.      *  
  23.      * @param source 
  24.      *            the source of the shapefile. 
  25.      * @throws IllegalArgumentException 
  26.      *             if the source is null or an empty string. 
  27.      * @throws WWRuntimeException 
  28.      *             if the shapefile cannot be opened for any reason. 
  29.      */  
  30.     public Shapefile(Object source)  
  31.     {  
  32.         this(source, null);  
  33.     }  
这种方法秩序给出shp文件的路径即可,但是若只有shp文件,缺少shx等文件则无法解析shape文件。
根据以上两种方法来实例化一个shapefile对象,源码如下:
[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. String shpFilePath = "D:\\Users\\wwj_data\\states.shp";  
  2.         String shxFilePath = "D:\\Users\\wwj_data\\states.shx";  
  3.         String dbfFilePath = "D:\\Users\\wwj_data\\states.dbf";  
  4.         String prjFilePath = "D:\\Users\\wwj_data\\states.prj";  
  5.   
  6.         Shapefile shapefile = new Shapefile(shpFilePath);  
  7.         System.out.println(shapefile.getShapeType());  
或者:---------------------------------------------------------------------------------------
[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. String shpFilePath = "D:\\Users\\wwj_data\\states.shp";  
  2.         String shxFilePath = "D:\\Users\\wwj_data\\states.shx";  
  3.         String dbfFilePath = "D:\\Users\\wwj_data\\states.dbf";  
  4.         String prjFilePath = "D:\\Users\\wwj_data\\states.prj";  
  5.   
  6.         InputStream shpInputStream = new FileInputStream(shpFilePath);  
  7.         InputStream shxInputStream = new FileInputStream(shxFilePath);  
  8.         InputStream dbfInputStream = new FileInputStream(dbfFilePath);  
  9.         InputStream prjInputStream = new FileInputStream(prjFilePath);  
  10.   
  11.         // 实例化一个shapefile类  
  12.          Shapefile shapefile = new Shapefile(shpInputStream, shxInputStream,  
  13.          dbfInputStream, prjInputStream);  
  14.         System.out.println(shapefile.getShapeType()); // shape类型  
 
这里需要说明的一点是,一开始的时候我是用的Shapefile(Object source)方法,但是报错:Source is NULL,不知是什么原因;用下面这种方法就可以,这个可以不必太纠结。

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

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

3、获取字段值

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. // 解析shape文件  
  2.         try  
  3.         {  
  4.             while (shapefile.hasNext())  
  5.             {  
  6.                 ShapefileRecord record = shapefile.nextRecord(); // 获取一条记录  
  7.                 DBaseRecord dBaseRecord = record.getAttributes(); // 获取该记录的属性信息  
  8.                                                   
  9.                 Object[] values = dBaseRecord.getValues().toArray();//获取字段值集合  
  10.   
  11.                 for (int i = 0; i < values.length; i++)  
  12.                 {  
  13.                     System.out.println(values[i].toString());  
  14.                 }  
  15.                 System.out.println("------------------");  
  16.             }  
  17.         }  
  18.         catch (Exception e)  
  19.         {  
  20.             e.printStackTrace();  
  21.             System.out.println("解析shapefile文件出错!");  
  22.         }  
  23.         finally  
  24.         {  
  25.             WWIO.closeStream(shapefile, shpFilePath);  
  26.             WWIO.closeStream(shapefile, shxFilePath);  
  27.             WWIO.closeStream(shapefile, dbfFilePath);  
  28.             WWIO.closeStream(shapefile, prjFilePath);  
  29.   
  30.         }  
思路很简单:shapefile文件—>获取一条记录—>获取记录的属性信息-->获取字段值集合。但是有一个问题:不支持中文字段值
调整后运行结果如下:

ArcMap下的属性表如下图所示:
通过对比,发现字段值虽然都读取了,但是顺序却是乱的。目前还未发现是什么原因,下一篇博客再来解决这个问题字段值与字段不对应的问题。下面给出完整的代码:
[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. /** 
  2.      * @方法名称: shapeFileReader ; 
  3.      * @方法描述: 读取sh文件 ; 
  4.      * @参数 :@throws FileNotFoundException 
  5.      * @返回类型: void ; 
  6.      * @创建人:奔跑的鸡丝 ; 
  7.      * @创建时间:2014-12-1 下午12:50:11; 
  8.      * @throws 
  9.      */  
  10.     private void shapeFileReader() throws FileNotFoundException  
  11.     {  
  12.         String shpFilePath = "D:\\Users\\wwj_data\\states.shp";  
  13.         String shxFilePath = "D:\\Users\\wwj_data\\states.shx";  
  14.         String dbfFilePath = "D:\\Users\\wwj_data\\states.dbf";  
  15.         String prjFilePath = "D:\\Users\\wwj_data\\states.prj";  
  16.   
  17.         InputStream shpInputStream = new FileInputStream(shpFilePath);  
  18.         InputStream shxInputStream = new FileInputStream(shxFilePath);  
  19.         InputStream dbfInputStream = new FileInputStream(dbfFilePath);  
  20.         InputStream prjInputStream = new FileInputStream(prjFilePath);  
  21.   
  22.         // 实例化一个shapefile类  
  23.          Shapefile shapefile = new Shapefile(shpInputStream, shxInputStream,  
  24.          dbfInputStream, prjInputStream);  
  25.       
  26.   
  27.         // 获取shp属性表  
  28.         DBaseFile dBaseFile = shapefile.getAttributesTable();  
  29.         int fieldCount = dBaseFile.getNumberOfFields(); // 字段数  
  30.         int recordsCount = dBaseFile.getNumberOfRecords(); // 记录数  
  31.         System.out.println("字段数为:" + fieldCount);  
  32.         System.out.println("记录数为:" + recordsCount);  
  33.         System.out.println(shapefile.getShapeType()); // shape类型  
  34.         //获取字段集合  
  35.         DBaseField [] dBaseFields=dBaseFile.getFields();  
  36.           
  37.         for (int i = 0; i < fieldCount; i++)  
  38.         {  
  39.             System.out.print(dBaseFields[i].getName()+"    ");  
  40.         }  
  41.         System.out.println();  
  42.         // 解析shape文件  
  43.         try  
  44.         {  
  45.             while (shapefile.hasNext())  
  46.             {  
  47.                 ShapefileRecord record = shapefile.nextRecord(); // 获取一条记录  
  48.                 DBaseRecord dBaseRecord = record.getAttributes(); // 获取该记录的属性信息  
  49.                                                   
  50.                 Object[] values = dBaseRecord.getValues().toArray();//获取字段值集合  
  51.   
  52.                 for (int i = 0; i < values.length; i++)  
  53.                 {  
  54.                     System.out.print(values[i].toString()+"        ");  
  55.                 }  
  56.                 System.out.println("------------------");  
  57.             }  
  58.         }  
  59.         catch (Exception e)  
  60.         {  
  61.             e.printStackTrace();  
  62.             System.out.println("解析shapefile文件出错!");  
  63.         }  
  64.         finally  
  65.         {  
  66.             WWIO.closeStream(shapefile, shpFilePath);  
  67.             WWIO.closeStream(shapefile, shxFilePath);  
  68.             WWIO.closeStream(shapefile, dbfFilePath);  
  69.             WWIO.closeStream(shapefile, prjFilePath);  
  70.   
  71.         }  
  72.   
  73.     }  

-----------------------------------------------华丽的分割线----------------------------------------------
关于上面提到的获取的字段与字段值不对应的问题解决办法:根据字段名来获取字段值。
[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. while (shapefile.hasNext())  
  2.             {  
  3.                 ShapefileRecord record = shapefile.nextRecord(); // 获取一条记录  
  4.                 DBaseRecord dBaseRecord = record.getAttributes(); // 获取该记录的属性信息  
  5.                 ArrayList<String> fieldArrayList = new ArrayList<String>();  
  6.                 for (int i = 0; i < fieldCount; i++)  
  7.                 {  
  8.                     /** 
  9.                      * 根据字段名称来获取字段值 
  10.                      */  
  11.                     String fieldValue = dBaseRecord.getValue(  
  12.                             dBaseFields[i].getName()).toString(); //  
  13.                     fieldArrayList.add(fieldValue);  
  14.                     System.out.print(fieldValue + "        ");  
  15.   
  16.                 }  
  17.   
  18.                 System.out.println("------------------");  
  19.             }  
执行结果如下图所示。
您好, shp 文件,属性值中文乱码问题,我是这么解决的
修改 gov.nasa.worldwind.formats.shapefile.DBaseFile;下的
decodeString 方法中的UTF-8 类型改为 GBK类型,希望对您有用
posted @ 2017-04-27 15:43  疯子110  阅读(862)  评论(0编辑  收藏  举报