Package gistoolkit.datasources.shapefile

Source Code of gistoolkit.datasources.shapefile.DbaseFile

/*
*    GISToolkit - Geographical Information System Toolkit
*    (C) 2002, Ithaqua Enterprises Inc.
*
*    This library is free software; you can redistribute it and/or
*    modify it under the terms of the GNU Lesser General Public
*    License as published by the Free Software Foundation;
*    version 2.1 of the License.
*
*    This library is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
*    Lesser General Public License for more details.
*
*    You should have received a copy of the GNU Lesser General Public
*    License along with this library; if not, write to the Free Software
*    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*   
*/

package gistoolkit.datasources.shapefile;

import cmp.LEDataStream.*;
import java.io.*;
import java.util.*;
import java.util.zip.GZIPInputStream;

/**
* Class to read and write data to a dbase III format file.
* Creation date: (5/15/2001 5:15:13 PM)
*/
public class DbaseFile {
   
    // Header information for the DBase File
    private DbaseFileHeader myHeader;
   
    // Record Information.
    private Vector myRecordVect = new Vector();
   
    // The file name to read or write.
    private String myFileName;
   
    // Convenient place to store the field names.
    private String[] myFieldNames;
   
    // verbose output flag
    private static boolean ourVerbose = false;
   
    /**
     * DbaseFile constructor comment.
     */
    public DbaseFile() {
        super();
    }
   
    /**
     * DbaseFile constructor comment.
     */
    public DbaseFile(String inFileName) {
        super();
        setFileName(inFileName);
    }
   
    /**
     * Adds the column to the file.
     */
    public void addColumn(String inName, char inType, int inLength, int inDecimalPlace) throws Exception{
        // update the header.
        if (myHeader == null) myHeader = new DbaseFileHeader();
        myHeader.addColumn(inName, inType, inLength, inDecimalPlace);
    }
   
    /**
     * Removes the named column from the file
     */
    public void removeColumn(String inName) {
        if (myHeader != null) {
            String trimName = inName.trim();
            int rmCol = myHeader.removeColumn(trimName);
           
            if (rmCol >= 0) {
                // now remove the data for this column from each record
                for (int rec = 0; rec < myHeader.getNumRecords(); rec++) {
                    // copy the fields before and after the deleted column
                    Object[] tempRec = new Object[myHeader.getNumFields()];
                    System.arraycopy(getRecord(rec), 0,
                    tempRec, 0, rmCol);
                    System.arraycopy(getRecord(rec), rmCol+1,
                    tempRec, rmCol,getRecord(rec).length-rmCol-1);
                    setRecord(tempRec, rec);
                }
               
                // re-build the list of field names
                myFieldNames = new String[myHeader.getNumFields()];
                for (int i=0; i<myHeader.getNumFields(); i++){
                    myFieldNames[i] = myHeader.getFieldName(i).trim();
                }
            }
        }
    }
   
    /**
     * Adds the record to the dataset.
     */
    protected void addRecord(Object[] inRecord){
        myRecordVect.addElement(inRecord);
    }
   
    /**
     * Returns the array of field names.
     */
    public String[] getFieldNames(){
        return myFieldNames;
    }
   
    /**
     * Retrieves the file name to read or write.
     */
    public String getFileName(){
        return myFileName;
    }
   
    // Retrieve number of records in the DbaseFile
    public int getNumRecords(){
        if (myRecordVect == null) return 0;
        else return myRecordVect.size();
    }
   
    // Retrieve the record at the given index
    public Object[] getRecord(int inIndex){
        return (Object[]) myRecordVect.elementAt(inIndex);
    }
   
    /** Retrieve the name of the given column. */
    public String getFieldName(int inIndex){
        return myHeader.getFieldName(inIndex);
    }
   
    /** Retrieve the type of the given column.*/
    public char getFieldType(int inIndex){
        return myHeader.getFieldType(inIndex);
    }
   
    /** Retrieve the length of the given column. */
    public int getFieldLength(int inIndex){
        return myHeader.getFieldLength(inIndex);
    }
   
    /** Retrieve the location of the decimal point. */
    public int getFieldDecimalLength(int inIndex){
        return myHeader.getFieldDecimalCount(inIndex);
    }
   
    /**
     * read the DBF file into memory.
     */
    public void read() throws Exception{
        // create an input stream from the file
        if (myFileName == null) throw new Exception("No file name specified");
       
        InputStream fin = null;
        // check to see if it is a compressed file
        if (myFileName.toUpperCase().endsWith(".GZ")) {
            FileInputStream fileIn =
            new FileInputStream(myFileName);
            fin = (InputStream) new GZIPInputStream(fileIn);
        }
        else {
            fin = (InputStream) new FileInputStream(myFileName);
        }
        LEDataInputStream in = new LEDataInputStream(fin);
       
        // create the header to contain the header information.
        myHeader = new DbaseFileHeader();
        myHeader.readHeader(in);
        myFieldNames = new String[myHeader.getNumFields()];
        for (int i=0; i<myHeader.getNumFields(); i++){
            myFieldNames[i] = myHeader.getFieldName(i).trim();
        }
       
        // flag to indicate to the user that there is extra space in this DBF file.
        boolean tempTelling = true;
       
        // read the data.
        char tempDeleted;
        for (int i=0; i<myHeader.getNumRecords(); i++){
           
            // retrieve the record length
            int tempNumFields = myHeader.getNumFields();
           
            // storage for the actual values
            Object[] tempRow = new Object[tempNumFields];
           
            // read the deleted flag
            tempDeleted = (char) in.readByte();
           
            // read the record length
            int tempRecordLength = 1; // for the deleted character just read.
           
            // read the Fields
            for (int j=0; j<tempNumFields; j++){
               
                // find the length of the field.
                int tempFieldLength = myHeader.getFieldLength(j);
                tempRecordLength = tempRecordLength + tempFieldLength;
               
                // find the field type
                char tempFieldType = myHeader.getFieldType(j);
                //System.out.print("Reading Name="+myHeader.getFieldName(j)+" Type="+tempFieldType +" Length="+tempFieldLength);
               
                // read the data.
                Object tempObject = null;
                switch (tempFieldType){
                    case 'L': // logical data type, one character (T,t,F,f,Y,y,N,n)
                        char tempChar = (char) in.readByte();
                        if ((tempChar == 'T') || (tempChar == 't') || (tempChar == 'Y') || (tempChar == 'y')){
                            tempObject = new Boolean(true);
                        }
                        else {
                            tempObject = new Boolean(false);
                        }
                        break;
                    case 'C': // character record.
                        byte[] sbuffer = new byte[tempFieldLength];
                        in.readFully(sbuffer);
                        tempObject = new String(sbuffer, "ISO-8859-1").trim();
                        break;
                    case 'D': // date data type.
                        byte[] dbuffer = new byte[8];
                        in.readFully(dbuffer);
                        String tempString = new String(dbuffer, 0, 4);
                        try{
                            int tempYear = Integer.parseInt(tempString);
                            tempString = new String(dbuffer, 4, 2);
                            int tempMonth = Integer.parseInt(tempString) - 1;
                            tempString = new String(dbuffer, 6, 2);
                            int tempDay = Integer.parseInt(tempString);
                            Calendar c = Calendar.getInstance();
                            c.set(Calendar.YEAR,tempYear);
                            c.set(Calendar.MONTH, tempMonth);
                            c.set(Calendar.DAY_OF_MONTH, tempDay);
                            tempObject = c.getTime();
                        }
                        catch (NumberFormatException e){
                        }
                       
                        break;
                    case 'M': // memo field.
                        byte[] mbuffer = new byte[10];
                        in.readFully(mbuffer);
                        break;
                    case 'N': // number
                    case 'F': // floating point number
                        byte[] fbuffer = new byte[tempFieldLength];
                        in.readFully(fbuffer);
                        try{
                            tempString = new String(fbuffer);
                            tempObject = Double.valueOf(tempString.trim());
                        }
                        catch (NumberFormatException e){
                        }
                        break;
                    default:
                        byte[] defbuffer = new byte[tempFieldLength];
                        in.readFully(defbuffer);
                        System.out.println("Do not know how to parse Field type "+tempFieldType);
                }
                tempRow[j] = tempObject;
                //        System.out.println(" Data="+tempObject);
            }
           
            // ensure that the full record has been read.
            if (tempRecordLength < myHeader.getRecordLength()){
                byte[] tempbuff = new byte[myHeader.getRecordLength()-tempRecordLength];
                in.readFully(tempbuff);
                if (tempTelling){
                    System.out.println("DBF File has "+(myHeader.getRecordLength()-tempRecordLength)+" extra bytes per record");
                    tempTelling = false;
                }
            }
           
            // add the row if it is not deleted.
            if (tempDeleted != '*'){
                myRecordVect.addElement(tempRow);
            }
        }
        fin.close();
    }
   
    /**
     * Removes all data from the dataset
     */
    protected void removeAllRecords(){
        myRecordVect.removeAllElements();
    }
   
    /**
     * Set the file name to read or write.
     */
    public void setFileName(String inFileName){
        if (inFileName == null) return;
        if (inFileName.length() == 0) return;
       
        // check if the file exists
        File tempFile = new File(inFileName);
        if (!tempFile.exists()){
            if (!inFileName.toUpperCase().endsWith(".DBF")) {
                myFileName = inFileName+".dbf";
            }
        }
        else{
            myFileName = inFileName;
        }
    }
   
    // notify about warnings.
    private boolean myWarning = true;
    /** Print warnings to system.out. */
    public void setWarnings(boolean inWarning){
        myWarning = inWarning;
        if (myHeader == null) myHeader = new DbaseFileHeader();
        myHeader.setWarnings(inWarning);
    }
   
    // Set the record at the given index
    public void setRecord(Object[] inRecord, int inIndex){
        myRecordVect.setElementAt(inRecord, inIndex);
    }
   
    // Set the verbose mode for output from this class
    public static void setVerbose(boolean inVerbose) {
        ourVerbose = inVerbose;
    }
   
    /**
     * write the DBF file to disk.
     */
    public void write() throws Exception{
       
        // create an output stream from the file
        if (myFileName == null) throw new Exception("No file name specified");
        FileOutputStream fout = new FileOutputStream(myFileName);
        LEDataOutputStream out = new LEDataOutputStream(fout);
       
        // write the header information
        if (myHeader == null) throw new Exception("No header available to write");
        myHeader.setNumRecords(myRecordVect.size());
        myHeader.writeHeader(out);
        int tempRecordLength = myHeader.getRecordLength();
       
        // write the data.
        for (int i=0; i<myHeader.getNumRecords(); i++){
            // keep track of how many bytes are written.
            int templength = 0;
           
            // storage for the actual values
            Object[] tempRow = getRecord(i);
           
            // write the deleted value
            out.writeByte(' ');
            templength++;
            for (int j=0; j<tempRow.length; j++){
               
                // field name for reference
                String tempFieldName = myHeader.getFieldName(j);
               
                // find the length of the field.
                int tempFieldLength = myHeader.getFieldLength(j);
               
                // find the field type
                char tempFieldType = myHeader.getFieldType(j);
               
                // write the data.
                int tempBytesWritten = 0;
                switch (tempFieldType){
                    case 'L': // logical data type, one character (T,t,F,f,Y,y,N,n)
                        if (tempRow[j] instanceof Boolean){
                            if ( ((Boolean) tempRow[j]).booleanValue() == true){
                                out.writeByte('T');
                                tempBytesWritten++;
                            }
                            else{
                                out.writeByte('F');
                                tempBytesWritten++;
                            }
                        }
                        else{
                            out.writeByte('F');
                            tempBytesWritten++;
                        }
                        templength = templength + 1;
                        break;
                    case 'C': // character record.
                    {
                        String tempString = "";
                        if (tempRow[j] != null) tempString = tempRow[j].toString();
                        byte[] tempBytes = tempString.getBytes("ISO-8859-1");
                        for (int k=0; k<tempFieldLength; k++){
                            if (tempBytes.length > k){
                                out.writeByte(tempBytes[k]);
                                tempBytesWritten++;
                            }
                            else{
                                out.writeByte(' ');
                                tempBytesWritten++;
                            }
                        }
                        templength = templength + tempFieldLength;
                    }
                    break;
                    case 'D': // date data type.
                        if (tempRow[j] instanceof Date){
                            Calendar c = Calendar.getInstance();
                            c.setTime((Date) tempRow[j]);
                            String tempString = ""+c.get(Calendar.YEAR);
                            for (int k=0; k<4; k++){
                                if (tempString.length()>k){
                                    out.writeByte(tempString.charAt(k));
                                    tempBytesWritten++;
                                }
                                else {
                                    out.writeByte('0');
                                    tempBytesWritten++;
                                }
                            }
                            tempString = ""+(c.get(Calendar.MONTH)+1);
                            if (tempString.length() == 0) {out.writeByte('0'); out.writeByte('0');}
                            if (tempString.length() == 1) {out.writeByte('0'); out.writeByte(tempString.charAt(0));}
                            if (tempString.length() > 1) {out.writeByte(tempString.charAt(0)); out.writeByte(tempString.charAt(1));}
                            tempBytesWritten +=2;
                            tempString = ""+c.get(Calendar.DAY_OF_MONTH);
                            if (tempString.length() == 0) {out.writeByte('0'); out.writeByte('0');}
                            if (tempString.length() == 1) {out.writeByte('0'); out.writeByte(tempString.charAt(0));}
                            if (tempString.length() > 1) {out.writeByte(tempString.charAt(0)); out.writeByte(tempString.charAt(1));}
                            tempBytesWritten +=2;
                        }
                        else{
                            // write 8 blanks
                            for (int k=0; k<8; k++){
                                out.writeByte(0);
                                tempBytesWritten++;
                            }
                        }
                        templength = templength + 8;
                        break;
                    case 'N': // number
                        if (tempFieldName.equals("SE_ROW_ID")){
                            System.out.println("");
                        }
                        // retrieve the decimal position of this column
                        int tempDecimals = myHeader.getFieldDescription(j).myDecimalCount;
                       
                        // if there are no decimal points, then just add the first part.
                        int tempLeadingLength = 0;
                        if (tempDecimals == 0){
                            tempLeadingLength = tempFieldLength;
                        }
                        else{
                            tempLeadingLength = tempFieldLength-tempDecimals-1; // the 1 is for the period or decimal point
                        }
                       
                        if (tempRow[j] instanceof Number){
                            String tempString = ((Number) tempRow[j]).toString();
                           
                           
                            // find the decimal in the String
                            int tempIndex = tempString.indexOf('.');
                           
                            // if is a decimal in the string then trim it off.
                            String tempWorkingString = tempString;
                            if (tempIndex != -1){
                                tempWorkingString = tempString.substring(0,tempIndex);
                            }
                           
                            // write the String
                            for (int k=0; k<tempLeadingLength; k++){
                                if (tempLeadingLength - k > tempWorkingString.length()){
                                    out.writeByte('0');
                                    tempBytesWritten++;
                                }
                                else{
                                    out.writeByte(tempWorkingString.charAt(k-(tempLeadingLength-tempWorkingString.length())));
                                    tempBytesWritten++;
                                }
                            }
                           
                           
                            // write the trailer.
                            if (tempDecimals >0){
                                out.writeByte('.');
                                tempBytesWritten++;
                            }
                            for (int k=0; k<tempDecimals; k++){
                                if (tempIndex == 0){
                                    out.writeByte('0');
                                    tempBytesWritten++;
                                }
                                else{
                                    if((tempIndex + k + 1) >= tempString.length()){
                                        out.writeByte('0');
                                        tempBytesWritten++;
                                    }
                                    else{
                                        out.writeByte(tempString.charAt(tempIndex+k+1));
                                        tempBytesWritten++;
                                    }
                                }
                            }
                        }
                        else{
                            for (int k=0; k<tempLeadingLength; k++){
                                out.writeByte(0);
                                tempBytesWritten++;
                            }
                            if (tempDecimals >0){
                                out.writeByte('.');
                                tempBytesWritten++;
                                for (int k=0; k<tempDecimals; k++){
                                    out.writeByte(0);
                                    tempBytesWritten++;
                                }
                            }
                        }
                        templength = templength + tempFieldLength;
                        break;
                    case 'F': // floating point number
                        // The decimal can be in any location for these types of numbers.
                        if (tempRow[j] instanceof Number){
                            String tempString = ((Number) tempRow[j]).toString();
                            int tempIndex = tempString.indexOf(".");
                            if (tempIndex > tempFieldLength){
                                for (int k=0; k<tempFieldLength; k++){
                                    out.writeByte('9');
                                    tempBytesWritten++;
                                }
                            }
                            else if (tempIndex == -1){
                                // write the string
                                for (int k=0; k<tempFieldLength; k++){
                                    if (k<tempString.length()){
                                        out.writeByte(tempString.charAt(k));
                                        tempBytesWritten++;
                                    }
                                    else{
                                        out.writeByte(' ');
                                        tempBytesWritten++;
                                    }
                                }
                            }
                        }
                        // write the string value.
                        else{
                            if (tempRow[j] == null){
                                for (int k=0; k<tempFieldLength; k++){
                                    out.writeByte(0);
                                    tempBytesWritten++;
                                }
                            }
                            else{
                                String tempString = tempRow[j].toString();
                                // write the string
                                for (int k=0; k<tempFieldLength; k++){
                                    if (k<tempString.length()){
                                        out.writeByte(tempString.charAt(k));
                                        tempBytesWritten++;
                                    }
                                    else{
                                        out.writeByte(0);
                                        tempBytesWritten++;
                                    }
                                }
                            }
                        }
                       
                    default:
                        System.out.println("Do not know how to parse/write field type "+tempFieldType);
                }
                if (ourVerbose) {
                    System.out.println("Wrote "+tempBytesWritten+" byte for "+tempFieldName+" Field Length is "+tempFieldLength+" Length="+templength);
                }
            }
           
            // if we have not yet finished writing the record, then finish it off.
            if (ourVerbose) {
                System.out.println("Writing "+(tempRecordLength-templength)+" Bytes at the end");
            }
            for (int j=0; j<(tempRecordLength-templength); j++){
                out.writeByte(0);
            }
        }
    }
}
TOP

Related Classes of gistoolkit.datasources.shapefile.DbaseFile

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.