空间矢量数据(.shp文件)之JAVA操作
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; }