Shape文件由ESRI开发,一个ESRI(Environmental Systems Research Institute)的shape文件包括一个主文件,一个索引文件,和一个dBASE表。其中主文件的后缀就是.shp。

        Shape文件已经是一种开源的文件格式,官方早在2006年就出版了相应的白皮书,对整个文件的读写进行了详细的说明,这样也使得Shape文件应用的更加广泛。本人在移动GIS开发的过程中,借机对.shp文件进行了研究,并简单实现了通过JAVA语言对.shp文件的读写操作功能。

================================================ 我是分隔线==============================================

1、Shape文件

        ESRI 的shape 文件由一个主文件、一个索引文件和一个dBASE 表构成。主文件是一个可变记录长度的随机文件,文件中的每个记录描述一个包含多个顶点的shape。在索引文件中,每个记录内容包含着与主文件中记录相对应的从主文件开始处的偏移量。dBASE 表中包含着与每个要素相对应的一条要素属性记录。几何数据与属性的一一对应关系是基于记录号来对应的。dBASE 文件中属性记录的顺序必须与主文件中的记录顺序相同。

         详见白皮书。。。。。。。。。。。。。。。。。。。

2、java实现shape文件的读取

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.database.Cursor;
import android.os.Environment;
import android.widget.Toast;

public class ReadShapeFile_DAL {
	//分别用于存放shp文件和dbs文件,要求一一对应
	private  List<File> g_shpFileName;
	private  List<File> g_dbfFileName;
	private  List<VectorOcupy> g_shpAndDbfFiles;
    private  Activity g_at;
    private  String SDPATH;//离线矢量文件存储路径  
	
    public ReadShapeFile_DAL()
	{
		
	}
	
	public void SetSDPath(String _path)
	{
		SDPATH=_path;
	}
	
    /**
     * 判断机器中是否有存储卡
     * @return
     */
	private static boolean haveSDCARD() {
		String status = Environment.getExternalStorageState();
		if (status.equals(Environment.MEDIA_MOUNTED)) 
		{
			return true;
		} 
		else 
		{
			return false;
		}
	}
	
    //读取目录中的.shp和.dbf文件
	public  boolean ListFile(Activity _at)
	{
		boolean flag=false;
		g_at=_at;
		g_shpFileName=new ArrayList<File>();
		g_dbfFileName=new ArrayList<File>();
		g_shpAndDbfFiles=new ArrayList<VectorOcupy>();
		if(haveSDCARD()){
    		//得到当前外部存储设备的目录( /SDCARD )   
			SDPATH = Environment.getExternalStorageDirectory() + "/LandMonitoringCollectionSystem";  
    	}else{
    		//手机中文件放置路径
    		SDPATH = "/data/data/featuredata";
    	}
		try
		{
			File dirs = new File(SDPATH);
			File [] filenames=dirs.listFiles();
			if(filenames.length==0)
			{
				return flag;
			}
			else
			{
				for(int i =0;i<filenames.length;i++)
				{
					 File file = filenames[i];
					 if(file.isFile())
					 {
						 if(file.getName().endsWith(".shp"))
						 {	
							 g_shpFileName.add(file);
						 }
						 else
						 {
							 if(file.getName().endsWith(".dbf"))
							 {
								 g_dbfFileName.add(file);
							 }
						 }
					 }
				  }
			}
			//判断矢量文件是否存在
			if(g_shpFileName.size()<1)
			{
				Toast.makeText(g_at, "数据读取失败,请确定离线数据存在",Toast.LENGTH_SHORT).show();
				return false;
			}
			else
			{
				g_shpAndDbfFiles=fileConfig(g_shpFileName,g_dbfFileName);
			}
			if(shpDataInsert())
			return true;
		}
		catch(Exception e)
		{
		   e.printStackTrace(); 
		   g_shpAndDbfFiles=new ArrayList<VectorOcupy>();
		   Toast.makeText(g_at,"数据读取失败,请确定离线数据存储的目录正确",Toast.LENGTH_SHORT).show();
		}
		return flag;
	}

	private  boolean shpDataInsert()
	{
		boolean flag=true;
		
		DataTableManagement g_myTableExcute=new DataTableManagement(g_at);
         //在此删除所有的矢量数据表
         String selectsql = "select * from sqlite_master"; 
			
     	 g_myTableExcute = new DataTableManagement(g_at);
			
			Cursor cs = g_myTableExcute.excuteCursorTable(selectsql);
			
			while(cs.moveToNext())
			{   
				String tableName = cs.getString(cs.getColumnIndex("name"));
				if(tableName.contains("_shp"))
				{
					String str="DROP TABLE IF EXISTS "+tableName+";";
		  	    	g_myTableExcute.ExcuteTable(str);
				}
			}
		
		
		
		for(int i=0;i<g_shpAndDbfFiles.size();i++)
		{
			try
			{
				ReadShapeFile_Analysis myShapeFileAnalysis;
				/**
				 * 同时包含shp与dbf文件
				 */
				if(g_shpAndDbfFiles.get(i).getFlag())
				{
					myShapeFileAnalysis=new ReadShapeFile_Analysis(g_shpAndDbfFiles.get(i).getShpFile(),g_shpAndDbfFiles.get(i).getDbfFile(),g_at);
				}
				else
				{
					myShapeFileAnalysis=new ReadShapeFile_Analysis(g_shpAndDbfFiles.get(i).getShpFile(),g_at);
				}
				if(!myShapeFileAnalysis.read())
				flag=false;
				/*for(int j=0;j<dbfFileName.size();j++)
				{
					File dbfFile=dbfFileName.get(j);
					String filename=shpFileName.get(i).getName().substring(0, shpFileName.get(i).getName().lastIndexOf("."));
					if(dbfFile.getName().substring(0, dbfFile.getName().lastIndexOf(".")).equals(filename))
					{
						
					}
				}
				ShapeFileAnalysis myShapeFileAnalysis=new ShapeFileAnalysis(shpFileName.get(i),at);
				myShapeFileAnalysis.read();
				if(myShapeFileAnalysis.getifChanged())
				flag=true;*/
			}
			catch(Exception e)
			{
				e.printStackTrace();
				System.out.println("解析shapefile失败");
				flag=false;
			}
		}
		return flag;
	}
  
	private List<VectorOcupy> fileConfig(List<File> shpfiles,List<File> dbffiles)
	{
		List<VectorOcupy> vectorocupy=new ArrayList<VectorOcupy>();
		try
		{
			for(int i=0;i<shpfiles.size();i++)
			{
				boolean flag=false;
				for(int j=0;j<dbffiles.size();j++)
				{
					String filename=shpfiles.get(i).getName().substring(0, shpfiles.get(i).getName().lastIndexOf("."));
					if(dbffiles.get(j).getName().substring(0, dbffiles.get(j).getName().lastIndexOf(".")).equals(filename))
					{
						vectorocupy.add(new VectorOcupy(shpfiles.get(i),dbffiles.get(j),true));
						flag=true;
						break;
						//j=dbffiles.size();
					}
				}
				//针对只有.shp文件的数据
				if(flag == false)
				{
					vectorocupy.add(new VectorOcupy(shpfiles.get(i),false));
				}
			}
		}
		catch(Exception ex)
		{
			ex.printStackTrace();
		}
		return vectorocupy;
	}
	
	class VectorOcupy
	{
		private File shpdatafile;
		private File dbfdatafile;
		private boolean flag;
		
        public VectorOcupy(File shpfile,File dbffile,boolean flag)
		{
			this.flag=flag;
			this.dbfdatafile=dbffile;
			this.shpdatafile=shpfile;
		}
		
        public VectorOcupy(File shpfile,boolean flag)
		{
			this.flag=flag;
			this.shpdatafile=shpfile;
			this.dbfdatafile=null;
		}
		
        public File getShpFile()
		{
			return shpdatafile;
		}
		
        public File getDbfFile()
		{
			return dbfdatafile;
		}
	    
        public boolean getFlag()
	    {
	    	return flag;
	    }
	}
}

3、DBF文件读取

package landmonitoring.mobilegismodels;

import java.io.*;

//Referenced classes of package cn.edu.sut.oa.workadmin.sjcl:
//             JDBFException, JDBField

public class DBFReader
{

     public DBFReader(String s)
         throws JDBFException
     {
         stream = null;
         fields = null;
         nextRecord = null;
         nFieldCount = 0;
         try
         {
             init(new FileInputStream(s));
         }
         catch(FileNotFoundException filenotfoundexception)
         {
             throw new JDBFException(filenotfoundexception);
         }
     }

     public DBFReader(FileInputStream inputstream)
         throws JDBFException
     {
         stream = null;
         fields = null;
         nextRecord = null;
         init(inputstream);
     }

     private void init(InputStream inputstream)
         throws JDBFException
     {
         try
         {
             stream = new DataInputStream(inputstream);
             int i = readHeader();
             fields = new JDBField[i];
             int j = 1;
             for(int k = 0; k < i; k++)
             {
                 fields[k] = readFieldHeader();
                 if(fields[k] != null)
                 {
                     nFieldCount++;
                     j += fields[k].getLength();
                 }
             }

             nextRecord = new byte[j];
             try
             {
                 stream.readFully(nextRecord);
             }
             catch(EOFException eofexception)
             {
                 nextRecord = null;
                 stream.close();
             }
             int l = 0;
             for(int i1 = 0; i1 < j; i1++)
             {
              if(nextRecord==null)
                     break;
              else
              {
                     if(nextRecord[i1] != 32 && nextRecord[i1] != 42)
                         continue;
                     l = i1;
                     break;
              }

             }

             if(l > 0)
             {
                 byte abyte0[] = new byte[l];
                 stream.readFully(abyte0);
                 for(int j1 = 0; j1 < j - l; j1++)
                     nextRecord[j1] = nextRecord[j1 + l];

                 for(int k1 = 0; k1 < l; k1++)
                     nextRecord[j - k1 - 1] = abyte0[l - k1 - 1];

             }
         }
         catch(IOException ioexception)
         {
             throw new JDBFException(ioexception);
         }
     }

     private int readHeader()
         throws IOException, JDBFException
     {
         byte abyte0[] = new byte[16];
         try
         {
             stream.readFully(abyte0);
         }
         catch(EOFException eofexception)
         {
             throw new JDBFException("Unexpected end of file reached.");
         }
         int i = abyte0[8];
         if(i < 0)
             i += 256;
         i += 256 * abyte0[9];
         i = --i / 32;
         i--;
         try
         {
             stream.readFully(abyte0);
         }
         catch(EOFException eofexception1)
         {
             throw new JDBFException("Unexpected end of file reached.");
         }
         return i;
     }

     private JDBField readFieldHeader()
         throws IOException, JDBFException
     {
         byte abyte0[] = new byte[16];
         try
         {
             stream.readFully(abyte0);
         }
         catch(EOFException eofexception)
         {
             throw new JDBFException("Unexpected end of file reached.");
         }
         if(abyte0[0] == 13 || abyte0[0] == 0)
         {
             stream.readFully(abyte0);
             return null;
         }
         StringBuffer stringbuffer = new StringBuffer(10);
         int i = 0;
         for(i = 0; i < 10; i++)
             if(abyte0[i] == 0)
                 break;

         stringbuffer.append(new String(abyte0, 0, i,"GB2312"));
         char c = (char)abyte0[11];
         try
         {
             stream.readFully(abyte0);
         }
         catch(EOFException eofexception1)
         {
             throw new JDBFException("Unexpected end of file reached.");
         }
         int j = abyte0[0];
         int k = abyte0[1];
         if(j < 0)
             j += 256;
         if(k < 0)
             k += 256;
         return new JDBField(stringbuffer.toString(), c, j, k);
     }

     public int getFieldCount()
     {
         return nFieldCount;
     }

     public JDBField getField(int i)
     {
         return fields[i];
     }

     public boolean hasNextRecord()
     {
         return nextRecord != null;
     }

     public Object[] nextRecord()
         throws JDBFException
     {
         if(!hasNextRecord())
             throw new JDBFException("No more records available.");
         Object aobj[] = new Object[nFieldCount];
         int i = 1;
         for(int j = 0; j < aobj.length; j++)
         {
             int k = fields[j].getLength();
             StringBuffer stringbuffer = new StringBuffer(k);
             try {
				stringbuffer.append(new String(nextRecord, i, k,"GB2312"));
				aobj[j] = fields[j].parse(stringbuffer.toString());
	             i += fields[j].getLength();
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
         }

         try
         {
             stream.readFully(nextRecord);
         }
         catch(EOFException eofexception)
         {
             nextRecord = null;
         }
         catch(IOException ioexception)
         {
             throw new JDBFException(ioexception);
         }
         return aobj;
     }

     public String[] nextRecordString()
         throws JDBFException
     {
         if(!hasNextRecord())
             throw new JDBFException("No more records available.");
         String as[] = new String[nFieldCount];
         int i = 1;
         for(int j = 0; j < as.length; j++)
         {
             int k = fields[j].getLength();
             StringBuffer stringbuffer = new StringBuffer(k);
             
             try {
            	 stringbuffer.append(new String(nextRecord, i, k,"GB2312"));
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
             as[j] = stringbuffer.toString();
             i += fields[j].getLength();
         }

         try
         {
             stream.readFully(nextRecord);
         }
         catch(EOFException eofexception)
         {
             nextRecord = null;
         }
         catch(IOException ioexception)
         {
             throw new JDBFException(ioexception);
         }
         return as;
     }

     public void close()
         throws JDBFException
     {
         nextRecord = null;
         try
         {
             stream.close();
         }
         catch(IOException ioexception)
         {
             throw new JDBFException(ioexception);
         }
     }

     private DataInputStream stream;
     private JDBField fields[];
     private byte nextRecord[];
     private int nFieldCount;
}

4、DBF写入

package landmonitoring.mobilegismodels;

import java.io.*;
import java.util.Calendar;

public class DBFWriter
{

       public DBFWriter(String s, JDBField ajdbfield[])
           throws JDBFException
       {
           stream = null;
           recCount = 0;  
           fields = null;
           fileName = null;
           dbfEncoding = null;
           fileName = s;
           try
           {
               init(new FileOutputStream(s), ajdbfield);
           }
           catch(FileNotFoundException filenotfoundexception)
           {
               throw new JDBFException(filenotfoundexception);
           }
       }

       public DBFWriter(OutputStream outputstream, JDBField ajdbfield[])
           throws JDBFException
       {
           stream = null;
           recCount = 0;
           fields = null;
           fileName = null;
           dbfEncoding = null;
           init(outputstream, ajdbfield);
       }

       public DBFWriter(String s, JDBField ajdbfield[], String s1)
           throws JDBFException
       {
           stream = null;
           recCount = 0;
           fields = null;
           fileName = null;
           dbfEncoding = null;
           fileName = s;
           try
           {
               dbfEncoding = s1;
               init(new FileOutputStream(s), ajdbfield);
           }
           catch(FileNotFoundException filenotfoundexception)
           {
               throw new JDBFException(filenotfoundexception);
           }
       }

       private void init(OutputStream outputstream, JDBField ajdbfield[])
           throws JDBFException
       {
           fields = ajdbfield;
           try
           {
               stream = new BufferedOutputStream(outputstream);
               writeHeader();
               for(int i = 0; i < ajdbfield.length; i++)
                   writeFieldHeader(ajdbfield[i]);

               stream.write(13);
               stream.flush();
           }
           catch(Exception exception)
           {
               throw new JDBFException(exception);
           }
       }

       private void writeHeader()
           throws IOException
       {
           byte abyte0[] = new byte[16];
           abyte0[0] = 3;
           Calendar calendar = Calendar.getInstance();
           abyte0[1] = (byte)(calendar.get(1) - 1900);
           abyte0[2] = (byte)calendar.get(2);
           abyte0[3] = (byte)calendar.get(5);
           abyte0[4] = 0;
           abyte0[5] = 0;
           abyte0[6] = 0;
           abyte0[7] = 0;
           int i = (fields.length + 1) * 32 + 1;
           abyte0[8] = (byte)(i % 256);
           abyte0[9] = (byte)(i / 256);
           int j = 1;
           for(int k = 0; k < fields.length; k++)
               j += fields[k].getLength();

           abyte0[10] = (byte)(j % 256);
           abyte0[11] = (byte)(j / 256);
           abyte0[12] = 0;
           abyte0[13] = 0;
           abyte0[14] = 0;
           abyte0[15] = 0;
           stream.write(abyte0, 0, abyte0.length);
           for(int l = 0; l < 16; l++)
               abyte0[l] = 0;

           stream.write(abyte0, 0, abyte0.length);
       }

       private void writeFieldHeader(JDBField jdbfield)
           throws IOException
       {
           byte abyte0[] = new byte[16];
           /*定义一个新数组,用来接收新构造的字符串字节数组*/
           byte abytem[];
           String s = jdbfield.getName();
           String news = new String();
        
           int j = 0;
           /*循环从新组成字符串,此字符串的字节长度不能大于10*/
           for(int k = 0; k<s.length();k++)
           {
            if((s.substring(k,k+1).getBytes().length+j)>10) /*字节长度大于1的时候为汉字*/
            {
             break;
            }
            else
            {
              j = j + s.substring(k,k+1).getBytes().length;
              news = news + s.charAt(k);
            }
           }
        
           /*接收字节数组*/
           abytem = news.getBytes();
           /*将字数组数据合并到文件头数据组*/
           for(int k = 0; k<abytem.length;k++)
           {
            abyte0[k] = abytem[k];
           }
           /*在没有地方补空*/
           for(int k = j; k <= 10; k++)
             abyte0[k] = 0;
        
        
           abyte0[11] = (byte)jdbfield.getType();
           abyte0[12] = 0;
           abyte0[13] = 0;
           abyte0[14] = 0;
           abyte0[15] = 0;
        
           stream.write(abyte0, 0, abyte0.length);
        
           for(int l = 0; l < 16; l++)
               abyte0[l] = 0;

        
           abyte0[0] = (byte)jdbfield.getLength();
           abyte0[1] = (byte)jdbfield.getDecimalCount();
           stream.write(abyte0, 0, abyte0.length);
       }

       public void addRecord(Object aobj[])
           throws JDBFException
       {
           if(aobj.length != fields.length)
               throw new JDBFException("Error adding record: Wrong number of values. Expected " + fields.length + ", got " + aobj.length + ".");
           int i = 0;
           for(int j = 0; j < fields.length; j++)
               i += fields[j].getLength();

           byte abyte0[] = new byte[i];
           int k = 0;
           for(int l = 0; l < fields.length; l++)
           {
               String s = fields[l].format(aobj[l]);
               byte abyte1[];
               try
               {
                   if(dbfEncoding != null)
                       abyte1 = s.getBytes(dbfEncoding);
                   else
                       abyte1 = s.getBytes();
               }
               catch(UnsupportedEncodingException unsupportedencodingexception)
               {
                   throw new JDBFException(unsupportedencodingexception);
               }
               for(int i1 = 0; i1 < fields[l].getLength(); i1++)
                   abyte0[k + i1] = abyte1[i1];

               k += fields[l].getLength();
           }

           try
           {
               stream.write(32);
               stream.write(abyte0, 0, abyte0.length);
               stream.flush();
           }
           catch(IOException ioexception)
           {
               throw new JDBFException(ioexception);
           }
           recCount++;
       }

       public void close()
           throws JDBFException
       {
           try
           {
               stream.write(26);
               stream.close();
               RandomAccessFile randomaccessfile = new RandomAccessFile(fileName, "rw");
               randomaccessfile.seek(4L);
               byte abyte0[] = new byte[4];
               abyte0[0] = (byte)(recCount % 256);
               abyte0[1] = (byte)((recCount / 256) % 256);
               abyte0[2] = (byte)((recCount / 0x10000) % 256);
               abyte0[3] = (byte)((recCount / 0x1000000) % 256);
               randomaccessfile.write(abyte0, 0, abyte0.length);
               randomaccessfile.close();
           }
           catch(IOException ioexception)
           {
               throw new JDBFException(ioexception);
           }
       }

       private BufferedOutputStream stream;
       private int recCount;
       private JDBField fields[];
       private String fileName;
       private String dbfEncoding;
}

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐