package uk.ac.leeds.ccg.dbffile; import java.io.*; import java.util.*; import java.lang.*; import cmp.LEDataStream.*; /** * * This class represents a DBF (or DBase) file.

* Construct it with a filename (including the .dbf) * this causes the header and field definitions to be read.

* Later queries return rows or columns of the database. *


* @author Ian Turton Centre for * Computaional Geography, University of Leeds, LS2 9JT, 1998. * */ public class DbfFile implements DbfConsts{ static final boolean DEBUG=false; int dbf_id; int last_update_d,last_update_m,last_update_y; int last_rec; int data_offset; int rec_size; boolean hasmemo; LEDataInputStream dFile; RandomAccessFile rFile; int filesize,numfields; public DbfFieldDef fielddef[]; /** * Constructor, opens the file and reads the header infomation. * @param file The file to be opened, includes path and .dbf * @exception java.io.IOException If the file can't be opened. * @exception DbfFileException If there is an error reading header. */ public DbfFile(String file) throws java.io.IOException,DbfFileException{ if(DEBUG)System.out.println("---->uk.ac.leeds.ccg.dbffile.DbfFile constructed. Will identify itself as DbFi>"); InputStream in = new FileInputStream(file); LEDataInputStream sfile = new LEDataInputStream(in); rFile=new RandomAccessFile(new File(file),"r"); init(sfile); } /** * Returns the date of the last update of the file as a string. */ public String getLastUpdate(){ String date=last_update_d+"/"+last_update_m+"/"+last_update_y; return date; } /** * Returns the number of records in the database file. */ public int getLastRec(){ return last_rec; } /** * Returns the size of the records in the database file. */ public int getRecSize(){ return rec_size; } /** * Returns the number of fields in the records in the database file. */ public int getNumFields(){ return numfields; } /** * Returns the size of the database file. */ public int getFileSize(){ return filesize; } /** * initailizer, allows the use of multiple constructers in later * versions. */ private void init(LEDataInputStream sfile)throws IOException,DbfFileException { DbfFileHeader head = new DbfFileHeader(sfile); int widthsofar; dFile=sfile; fielddef = new DbfFieldDef[numfields]; widthsofar=1; for(int index=0;indexHeader id "); if(DEBUG)System.out.println(dbf_id); if(dbf_id==3) hasmemo=false; else hasmemo=true; last_update_y=(int)file.readUnsignedByte()+DBF_CENTURY; last_update_m=(int)file.readUnsignedByte(); last_update_d=(int)file.readUnsignedByte(); if(DEBUG)System.out.print("DbFi>last update "); if(DEBUG)System.out.print(last_update_d); if(DEBUG)System.out.print("/"); if(DEBUG)System.out.print(last_update_m); if(DEBUG)System.out.print("/"); if(DEBUG)System.out.println(last_update_y); last_rec=file.readInt(); if(DEBUG)System.out.print("DbFi>last rec "); if(DEBUG)System.out.println(last_rec); data_offset=file.readShort(); //data_offset=0; //System.out.println("x = "+file.readUnsignedByte()+" " + //file.readUnsignedByte()); if(DEBUG)System.out.print("DbFi>data offset "); if(DEBUG)System.out.println(data_offset); rec_size=file.readShort(); if(DEBUG)System.out.print("DbFi>rec_size "); if(DEBUG)System.out.println(rec_size); filesize=(rec_size * last_rec) + data_offset+1; numfields = (data_offset - DBF_BUFFSIZE -1)/DBF_BUFFSIZE; if(DEBUG)System.out.print("DbFi>num fields "); if(DEBUG)System.out.println(numfields); if(DEBUG)System.out.print("DbFi>file size "); if(DEBUG)System.out.println(filesize); file.skipBytes(20); } } /** * gets the next record and returns it as a string. This method works on * a sequential stream and can not go backwards. Only useful if you want * to read the whole file in one. * @exception java.io.IOException on read error. */ public StringBuffer GetNextDbfRec()throws java.io.IOException{ StringBuffer record = new StringBuffer(rec_size+numfields); for(int i=0;i< rec_size;i++){ // we could do some checking here. record.append((char)rFile.readUnsignedByte()); } return record; } /** * fetches the rowth row of the file * @param row - the row to fetch * @exception java.io.IOException on read error. */ public StringBuffer GetDbfRec(int row)throws java.io.IOException{ StringBuffer record = new StringBuffer(rec_size+numfields); rFile.seek(data_offset+(rec_size*row)); //Multi byte character modification thanks to Hisaji ONO byte[] strbuf = new byte[rec_size]; // <---- byte array buffer fo storing string's byte data for(int i=0;irowth row of the file and parses it into an vector * of objects. * @param row - the row to fetch * @exception java.io.IOException on read error. */ public Vector ParseDbfRecord(int row)throws java.io.IOException{ return ParseRecord(GetDbfRec(row)); } /** * Parses the record stored in the StringBuffer rec into a vector of * objects * @param StringBuffer rec - the record to be parsed. */ public Vector ParseRecord(StringBuffer rec){ Vector record=new Vector(numfields); String t; Integer I=new Integer(0); Double F=new Double(0.0); t = rec.toString(); for(int i=0;itype "+fielddef[i].fieldtype); if(DEBUG)System.out.println("DbFi>start "+fielddef[i].fieldstart); if(DEBUG)System.out.println("DbFi>len "+fielddef[i].fieldlen); if(DEBUG)System.out.println(t.substring(fielddef[i].fieldstart, fielddef[i].fieldstart+fielddef[i].fieldlen)); switch(fielddef[i].fieldtype){ case 'C': record.addElement(t.substring(fielddef[i].fieldstart, fielddef[i].fieldstart+fielddef[i].fieldlen)); break; case 'N': try{ record.addElement(I.decode(t.substring( fielddef[i].fieldstart,fielddef[i].fieldstart+fielddef[i].fieldlen))); }catch(java.lang.NumberFormatException e){ record.addElement(new Integer(0)); } break; case 'F': try{ record.addElement(F.valueOf(t.substring( fielddef[i].fieldstart,fielddef[i].fieldstart+fielddef[i].fieldlen))); }catch(java.lang.NumberFormatException e){ record.addElement(new Float(0.0)); } break; default: if(DEBUG)System.out.println("DbFi>Oh - don't know how to parse " +fielddef[i].fieldtype); } } return record; } /** * Fetches a column of Integers from the database file. * @param int col - the column to fetch * @exception java.io.IOException - on read error * @exception DbfFileException - column is not an Integer. */ public Integer[] getIntegerCol(int col ) throws java.io.IOException,DbfFileException { return getIntegerCol(col,0,last_rec); } /** * Fetches a part column of Integers from the database file. * @param int col - the column to fetch * @param int start - the row to start fetching from * @param int end - the row to stop fetching at. * @exception java.io.IOException - on read error * @exception DbfFileException - column is not an Integer. */ public Integer[] getIntegerCol(int col, int start, int end) throws java.io.IOException,DbfFileException { Integer column[]=new Integer[end-start]; String record = new String(); StringBuffer sb = new StringBuffer(numfields); int k=0,i=0; if(col>=numfields) throw new DbfFileException("DbFi>No Such Column in file: "+col); if(fielddef[col].fieldtype!='N') throw new DbfFileException("DbFi>Column "+col+" is not Integer"); // move to start of data try{ rFile.seek(data_offset+(rec_size*start)); for(i=start;i"+e); System.err.println("DbFi>record "+i+" byte "+k+" file pos " +rFile.getFilePointer());} catch(java.io.IOException e){ System.err.println("DbFi>"+e); System.err.println("DbFi>record "+i+" byte "+k+" file pos " +rFile.getFilePointer());} return column; } /** * Fetches a column of Double from the database file. * @param int col - the column to fetch * @exception java.io.IOException - on read error * @exception DbfFileException - column is not an Integer. */ public Double[] getFloatCol(int col) throws DbfFileException, java.io.IOException{ return getFloatCol(col,0,last_rec); } /** * Fetches a part column of Double from the database file. * @param int col - the column to fetch * @param int start - the row to start fetching from * @param int end - the row to stop fetching at. * @exception java.io.IOException - on read error * @exception DbfFileException - column is not an Integer. */ public Double[] getFloatCol(int col,int start,int end) throws DbfFileException, java.io.IOException{ Double column[]=new Double[end-start]; String record,st; StringBuffer sb = new StringBuffer(rec_size); int k=0,i=0; if(col>=numfields) throw new DbfFileException("DbFi>No Such Column in file: "+col); if(fielddef[col].fieldtype!='F') throw new DbfFileException("DbFi>Column "+col+" is not Double " +fielddef[col].fieldtype); // move to start of data try{ rFile.seek(data_offset+(rec_size*start)); for(i=start;i"+e); System.err.println("DbFi>record "+i+" byte "+k+" file pos " +rFile.getFilePointer());} catch(java.io.IOException e){ System.err.println("DbFi>"+e); System.err.println("DbFi>record "+i+" byte "+k+" file pos " +rFile.getFilePointer());} return column; } /** * Fetches a column of Strings from the database file. * @param int col - the column to fetch * @exception java.io.IOException - on read error * @exception DbfFileException - column is not an Integer. */ public String[] getStringCol(int col) throws DbfFileException, java.io.IOException{ return getStringCol(col,0,last_rec); } /** * Fetches a part column of Strings from the database file. * @param int col - the column to fetch * @param int start - the row to start fetching from * @param int end - the row to stop fetching at. * @exception java.io.IOException - on read error * @exception DbfFileException - column is not an Integer. */ public String[] getStringCol(int col,int start,int end) throws DbfFileException, java.io.IOException { String column[]=new String[end-start]; String record = new String(); //StringBuffer sb = new StringBuffer(numfields); int k=0,i=0; if(col>=numfields) throw new DbfFileException("DbFi>No Such Column in file: "+col); if(fielddef[col].fieldtype!='C') throw new DbfFileException("DbFi>Column "+col+" is not a String"); // move to start of data try{ rFile.seek(data_offset+(start*rec_size)); for(i=start;i"+e); System.err.println("DbFi>record "+i+" byte "+k+" file pos " +rFile.getFilePointer());} catch(java.io.IOException e){ System.err.println("DbFi>"+e); System.err.println("DbFi>record "+i+" byte "+k+" file pos " +rFile.getFilePointer());} return column; } }