Hi Jody,

I have just finished my implementation of index for shapefile attributes.

Since I had to code it quickly, it only works with these suppositions:

  1.

     The attributes index is a map between attribute value and feature
     ID (this is due to the fact that I use geotools as a library, so I
     don't overwrite its source code).

  2.

     The attributes in the shapefile never change. If so, the index has
     to be rebuilt.

  3.

     The attribute to be index may have duplicate values.


The index itself consists of:

  1.

     One index summary file. This lists every attribute that has an index.

  2.

     One index file for every attribute to be indexed. This kind of
     index is a collection sorted by attribute value with indication of
     Feature ID (that is the position of the feature record in the dbf
     file).


Of course, you can improve it and make it more suitable for general use.
For example you can merge its behaviour with the behaviour of FIDIndexer and have a more direct index for attributes.


I hope that this is useful. ;) You will find it in attachment.


Best regards

Bye,

Manuele.



in data 25/01/2008 18.07 Jody Garnett ha detto:
Manuele Ventoruzzo wrote:
Hi All,

I have to do a search by attribute into a large shapefile. So I need a feature like attribute index, but I know that at the moment Geotools doesn't support attribute indexes for shapefiles.
But we do welcome the idea; these are straight DBF indexes as far as I know so you should be able to find and example and send us a patch. As a general warning the shapefile code has been cleaned up on 2.5.x (the first time this has been done for a while). So if you are serious about
shapefile use that is the place to be.
So I'm trying to find a way to use a FidFilter.
First of all, what is build a Fid index for shapefiles like?
I have read the source code and it appears that Fid is always the position of the record in the attributes (.dbf) file.

Is this correct?
It is; the "FeatureId" is made up of the file name (because the WFS specification asks feature ids to start with a letter) followed by a "." and the row number.
If not, is there a way to tell Geotools which attribute should be used as Feature ID?
The file used to access rows quickly is part of the shapefile definition; and it is defined in terms of row numbers. Row numbers are used in the shp file as well
to indicate which attribtues a geometry is bound to.
Otherwise, can I assume that Fid is always the position of the record into dbf file and use another file to map attributes into corresponding Fid.
Correct; and if you do that your other file is an attribute index and we would *love* to try out your implementation!
Thank you for the attention.
Manuele


-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Geotools-gt2-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users




--
------------------------------------------------------------------------
*Manuele Ventoruzzo*
Over I.T. srl - Gruppo Engineering
Via Bassi 81
33080 Fiume Veneto (PN)
email: [EMAIL PROTECTED]
------------------------------------------------------------------------
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.NoSuchElementException;
import org.geotools.data.shapefile.StreamLogging;

/**
 * Class to read an attribute index file
 * @author Manuele Ventoruzzo
 */
public class AttributeIndexReader {
    
    private int record_size;
    private String attribute;
    private int numRecords;
    private char attributeType;
    private StreamLogging streamLogger = new 
StreamLogging("AttributeIndexReader");
    private FileChannel readChannel;
    private ByteBuffer buffer;
    private int foundPos;
    
    /** Crea una nuova istanza di AttributeIndexReader */
    public AttributeIndexReader(String attribute, FileChannel readChannel) 
throws IOException {
        this.readChannel = readChannel;
        this.attribute = attribute;
        streamLogger.open();
        readHeader();
        allocateBuffers();
    }
    
    /** 
     * Returns the number of attributes in this index
     */
    public int getCount() {
        return numRecords;
    }
    
    public void goTo(int recno) throws IOException {
        long newPos = AttributeIndexWriter.HEADER_SIZE + (recno * record_size);
        if (newPos > readChannel.size())
            throw new NoSuchElementException();
        readChannel.position(newPos);
        buffer.limit(buffer.capacity());
        buffer.position(buffer.limit());
    }
    
    public IndexRecord next() throws IOException {
        if (!hasNext()) {
            throw new NoSuchElementException();
        }
        return getRecord();
    }
    
    /**
     * Check if there's more elements to read
     */
    public boolean hasNext() throws IOException {
        if (isEOF())
            return false;
        if (buffer.position() == buffer.limit()) {
            buffer.position(0);
            buffer.limit((int) Math.min(buffer.limit(),remainingInFile()));
            int read = readChannel.read(buffer);
            if (read!=0)
                buffer.position(0);
        }
        return buffer.remaining() != 0;
    }
    
    public boolean isEOF() throws IOException {
        return (buffer.position() == buffer.limit()) && (readChannel.position() 
== readChannel.size());
    }
    
    /**
     * Finds an attribute and returns its FIDs.
     * @param reqAttribute Attribute to find.
     * @return Collection of FID found (empty if nothing could be found). 
     * It can found more than one record if it isn't univocal.
     * @throws java.io.IOException
     */
    public Collection findFids(Object reqAttribute) throws IOException {
        IndexRecord rec = findRecord(reqAttribute);
        if (rec==null)
            return new ArrayList(0);
        goTo(foundPos+1);
        ArrayList l = new ArrayList();
        while (rec.getAttribute().equals(reqAttribute)) {
            l.add(new Long(rec.getFeatureID()));
            if (!hasNext())
                break;
            rec = next();
        }
        return l;
    }
    
    /**
     * Finds an attibute.
     * @param reqAttribute Attribute to find.
     * @return Record as in index file.
     * @throws java.io.IOException
     */
    public IndexRecord findRecord(Object reqAttribute) throws IOException {
        foundPos = 0;
        return search(reqAttribute,0,numRecords,(numRecords/2)-1);
    }
    
    private void readHeader() throws IOException {
        ByteBuffer buf = ByteBuffer.allocate(AttributeIndexWriter.HEADER_SIZE);
        readChannel.read(buf);
        buf.position(0);
        attributeType = (char) buf.get();
        record_size = buf.getInt();
        numRecords = buf.getInt();
    }
    
    private void allocateBuffers() throws IOException {
        buffer = ByteBuffer.allocateDirect(record_size*1024);
        buffer.position(buffer.limit());
    }
    
    /**
     * Searches for the desired record.
     *
     * @param desired the id of the desired record.
     * @param minRec the last record that is known to be <em>before</em> the
     *        desired record.
     * @param maxRec the first record that is known to be <em>after</em> the
     *        desired record.
     * @param predictedRec the record that is predicted to be the desired
     *        record.
     *
     * @return returns the record found.
     *
     * @throws IOException
     */
    private IndexRecord search(Object desired, int minRec, int maxRec,
                int predictedRec) throws IOException {
        if (maxRec == minRec) {
            goTo(minRec);
            buffer.limit(record_size);
            IndexRecord currentRecord = next();
            buffer.limit(buffer.capacity());
            return (currentRecord != null && 
currentRecord.getAttribute().equals(desired))
                    ? firstInstance(minRec, currentRecord) : null;
        }
        goTo(predictedRec);
        buffer.limit(record_size);
        IndexRecord currentRecord = next();
        buffer.limit(buffer.capacity());
        if (currentRecord == null)
            return null;
        int comparison = currentRecord.compareTo(desired);
        if (comparison == 0) {
            return firstInstance(predictedRec, currentRecord);
        }
        if (maxRec - minRec < 2) {
            int llimit = (minRec == predictedRec) ? minRec + 1 : minRec;
            int ulimit = (minRec == predictedRec) ? maxRec : maxRec - 1;
            int newPrediction = (minRec == predictedRec) ? llimit : ulimit;
            return search(desired, llimit, ulimit, newPrediction);
        }
        if (comparison < 1) {
            int newPrediction = (maxRec - predictedRec) / 2 + predictedRec;
            return search(desired, ++predictedRec, maxRec, newPrediction);
        } else {
            int newPrediction = (predictedRec - minRec) / 2 + minRec;
            return search(desired, minRec, --predictedRec, newPrediction);
        }
    }
    
    private IndexRecord getRecord() throws IOException {
        Comparable obj = null;
        switch (attributeType) {
            case 'N':
                if (record_size == 12) {
                    obj = new Integer(buffer.getInt());
                } else {
                    obj = new Long(buffer.getLong());
                }
                break;
            case 'F':
                obj = new Double(buffer.getDouble());
                break;
            case 'L':
                obj = (buffer.get() == (byte) 1) ? Boolean.TRUE : Boolean.FALSE;
                break;
            case 'D':
                obj = new Date(buffer.getLong());
                break;
            case 'C':
            default:
                byte[] b = new byte[record_size - 8];
                buffer.get(b);
                obj = (new String(b, "ISO-8859-1")).trim();
            }
        long id = buffer.getLong();
        return new IndexRecord(obj, id);
    }
    
    private IndexRecord firstInstance(int position, IndexRecord rec) throws 
IOException {
        if (rec == null)
            return null;
        IndexRecord current = rec;
        IndexRecord prev = rec;
        while (rec.compareTo(current) == 0 && position > 0) {
            goTo(--position);
            buffer.limit(record_size);
            prev = current;
            current = next();
            buffer.limit(buffer.capacity());
        }
        boolean b = (rec.compareTo(current) == 0);
        foundPos = b ? position : position + 1;
        return b ? current : prev;
    }
    
    private long remainingInFile() throws IOException {
        return readChannel.size() - readChannel.position();
    }
    
}
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.channels.FileChannel;
import java.text.DecimalFormat;

/**
 * <P>Class to manage a summary for attribute indexes.</P> 
 * <P>It's just map that associates attribute name with index file. 
 * Using the name instead of its position on dbf permits to abstract from 
position, 
 * so attribute order can change with no influence on indexes.
 * </P>
 * @author Manuele Ventoruzzo
 */
public class AttributeIndexSummary {
    
    public static final String SUMMARY_EXT = ".ids";
    
    public static final String INDEX_EXT = ".i";
    
    public static final DecimalFormat SUFFIX = new DecimalFormat("00");
    
    public static final int DEFAULT_CACHE_SIZE = 134217728; //128MB
    
    /** Url of summary file */
    protected URL summaryURL   = null;
    
    protected String filename  = null;
    
    protected int cacheSize;
    
    /**
     * Creates an IndexSummary
     * @param shapefileUrl url of shapefile for wich indexes are related to
     */
    public AttributeIndexSummary(URL shpURL) throws MalformedURLException, 
IOException {
        this(shpURL,DEFAULT_CACHE_SIZE);
    }
    
    /**
     * Creates an IndexSummary
     * @param shapefileUrl url of shapefile for wich indexes are related to
     * @param cacheSize maximum amount of memory to be used for index creation
     */
    public AttributeIndexSummary(URL shpURL, int cacheSize) throws 
MalformedURLException, IOException {
        try {
            filename = java.net.URLDecoder.decode(shpURL.toString(),
                    "US-ASCII");
            filename = filename.substring(0, filename.lastIndexOf(".shp"));
        } catch (java.io.UnsupportedEncodingException use) {
            throw new java.net.MalformedURLException("Unable to decode " + 
shpURL + " cause " + use.getMessage());
        }
        int indexslash = filename.lastIndexOf(File.pathSeparator);

        if (indexslash == -1) {
            indexslash = 0;
        }
        summaryURL = new URL(filename + SUMMARY_EXT);
        //create summary file (if it doesn't exist) empty
        new File(summaryURL.getFile()).createNewFile();
        this.cacheSize = cacheSize;
    }
    
    /**
     * Index creation. Adds attribute name to summary and invokes attribute 
index creation.
     * @param attribute
     */
    public void createIndex(String attribute) throws FileNotFoundException, 
IOException {
        URL url = getIndexURL(attribute);
        if (url==null) {
            addIndex(attribute);
            url = getIndexURL(attribute);
        }
        synchronized (this) {
            //now invokes AttributeIndexWriter to create the index
            File f = new File(url.getFile());
            if (f.exists()) {
                if (!f.delete())
                    throw new IOException("File index cannot be deleted. 
Probably it's locked.");
            }
            RandomAccessFile raf = new RandomAccessFile(f, "rw");
            FileChannel writeChannel = raf.getChannel();
            AttributeIndexWriter indexWriter = new 
AttributeIndexWriter(attribute, writeChannel, getDBFChannel(),cacheSize);
            indexWriter.buildIndex();
        }
    }
    
    /**
     * Returns the index for specified attribute
     * @param attribute attribute to search for
     * @return Index reader or null if such attribute doesn't have an index
     */
    public AttributeIndexReader getIndex(String attribute) throws 
FileNotFoundException, IOException {
        URL url = getIndexURL(attribute);
        if (url == null)
            return null;
        File f = new File(url.getFile());
        if (!f.exists())
            return null;
        RandomAccessFile raf = new RandomAccessFile(new File(url.getFile()), 
"r");
        return new AttributeIndexReader(attribute, raf.getChannel());
    }
    
    public boolean hasIndex(String attribute) throws FileNotFoundException, 
IOException {
        URL url = getIndexURL(attribute);
        if (url == null)
            return false;
        return (new File(url.getFile())).exists();
    }
    
    /**
     * Tests whether an index for this attribute exists.
     * @param attribute
     * @return
     */
    public boolean existsIndex(String attribute) throws FileNotFoundException, 
IOException {
        URL url = getIndexURL(attribute);
        if (url == null)
            return false;
        File f = new File(url.getFile());
        return f.exists();
    }
    
    /**
     * Returns the index URL for specified attribute
     * @param attribute attribute to search for
     * @return URL to index file or null if such attribute doesn't have an index
     */
    protected URL getIndexURL(String attribute) throws FileNotFoundException, 
IOException {
        File f = new File(summaryURL.getFile());
        BufferedReader in = new BufferedReader(new FileReader(f));
        int count = 0;
        while (in.ready()) {
            String s = in.readLine();
            count++;
            if (s.equals(attribute)) {
                //index name: filename + number of row in index summary + 
extension
                return new URL(filename+INDEX_EXT+SUFFIX.format(count));
            }
        }
        return null; //index not found
    }
    
    protected synchronized void addIndex(String attribute) throws 
FileNotFoundException, IOException {
        File f = new File(summaryURL.getFile());
        PrintWriter out = new PrintWriter(new FileWriter(f,true));
        out.println(attribute);
        out.flush();
        out.close();
    }

    protected FileChannel getDBFChannel() throws FileNotFoundException, 
MalformedURLException {
        URL url = new URL(filename+".dbf");
        File f = new File(url.getFile());
        if (!f.exists())
            url = new URL(filename+".DBF");
        f = new File(url.getFile());
        if (!f.exists())
            throw new FileNotFoundException("DBF file not found");
        RandomAccessFile raf = new RandomAccessFile(f, "r");
        return raf.getChannel();
    }
    
}
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import org.geotools.data.shapefile.StreamLogging;
import org.geotools.data.shapefile.dbf.DbaseFileHeader;
import org.geotools.data.shapefile.dbf.DbaseFileReader;
import org.geotools.resources.NIOUtilities;

/**
 * Class used to create an index for an dbf attribute 
 * @author Manuele Ventoruzzo
 */
public class AttributeIndexWriter {
    
    public static final int HEADER_SIZE = 9;
    /** Number of bytes to be cached into memory (then it will be written to 
temporary file) */
    private int cacheSize;
    private int record_size;
    private FileChannel writeChannel;
    private FileChannel currentChannel;
    private DbaseFileReader reader;
    private StreamLogging streamLogger = new 
StreamLogging("AttributeIndexWriter");
    private String attribute;
    private int numRecords;
    private int attributeColumn;
    private Class attributeClass;
    private char attributeType;
    private File[] tempFiles;
    private ArrayList buffer;
    private long current;
    private long position;
    private int curFile;
    private ByteBuffer writeBuffer;
    
    /**
     * Create a new instance of AttributeIndexWriter 
     * @param attribute Attribute to be indexed
     * @param writeChannel Channel used to write the index
     * @param readChannel Channel used to read attributes file
     */
    public AttributeIndexWriter(String attribute, FileChannel writeChannel,
                                 ReadableByteChannel readChannel, int 
cacheSize) throws IOException {
        this.writeChannel = writeChannel;
        this.attribute = attribute;
        this.cacheSize = cacheSize;
        reader = new DbaseFileReader(readChannel, false);
        if (!retrieveAttributeInfos()) {
            throw new IOException("Attribute " + attribute + " not found in dbf 
file");
        }
        streamLogger.open();
        tempFiles = new File[getNumFiles()];
        buffer = new ArrayList(getCacheSize());
        current = 0;
        curFile = 0;
    }
    
    /**
     * Build index, caching data in chucks and sorting it.
     */
    public void buildIndex() throws IOException {
        while (hasNext()) {
            position = 0;
            readBuffer();
            saveBuffer();
        }
        reader.close();
        merge();
        deleteTempFiles();
        streamLogger.close();
    }
    
    /** 
     * Returns the number of attributes indexed
     */
    public int getCount() {
        return numRecords;
    }
    
    private boolean hasNext() {
        return reader.hasNext();
    }
    
    private void deleteTempFiles() {
        for (int i = 0; i < tempFiles.length; i++) {
            if (!tempFiles[i].delete()) {
                tempFiles[i].deleteOnExit();
            }
        }
    }
    
    private void merge() throws IOException {
        DataInputStream[] in = new DataInputStream[tempFiles.length];
        try {
            IndexRecord[] recs = new IndexRecord[tempFiles.length];
            for (int i = 0; i < tempFiles.length; i++) {
                in[i] = new DataInputStream(new FileInputStream(tempFiles[i]));
                recs[i] = null;
            }
            currentChannel = writeChannel; //to write to the ultimate 
destination
            allocateBuffers();
            writeBuffer.position(HEADER_SIZE);
            position = 0;
            int streamsReady;
            IndexRecord min;
            int mpos;
            do {
                min = null;
                mpos = -1;
                streamsReady = recs.length;
                for (int j = 0; j < recs.length; j++) {
                    if (recs[j] == null) {
                        try {
                            recs[j] = readRecord(in[j]);
                        } catch (EOFException e) {
                            streamsReady--;
                            continue;
                        }
                    }
                    if (min==null || (min.compareTo(recs[j])>0)) {
                        min = recs[j];
                        mpos = j;
                    }
                }
                if (mpos!=-1)
                    recs[mpos] = null;
                write(min);
            } while (streamsReady>0);
        } finally {
            //close input streams
            for (int i = 0; i < in.length; i++) {
                if (in[i]!=null)
                    in[i].close();
            }
            //close output stream
            drain();
            writeHeader();
            close();
        }
    }
    
    /** Loads next part of file into cache */
    private void readBuffer() throws IOException {
        buffer.clear();
        int n = getCacheSize();
        Comparable o;
        IndexRecord r;
        for (int i = 0; hasNext() && i < n; i++) {
            o = getAttribute();
            r = new IndexRecord(o,current);
            buffer.add(r);
            current++;
        }
    }
    
    /** Saves buffer on temporary file */
    private void saveBuffer() throws IOException {
        RandomAccessFile raf = null;
        try {
            if (buffer.size() == 0) {
                return;
            }
            try {
                Collections.sort(buffer);
            } catch (OutOfMemoryError err) {
                throw new IOException(err.getMessage()+". Try to lower memory 
load parameter.");
            }
            File file = File.createTempFile("attind", null);
            tempFiles[curFile++] = file;
            Iterator it = buffer.iterator();
            raf = new RandomAccessFile(file, "rw");
            currentChannel = raf.getChannel();
            currentChannel.lock();
            allocateBuffers();
            writeBuffer.position(0);
            while (it.hasNext()) {
                write((IndexRecord) it.next());
            }
        } finally {
            close();
            if (raf != null) {
                raf.close();
            }
        }
    }
    
    
    private int getNumFiles() throws IOException {
        int maxRec = getCacheSize();
        int n = (numRecords / maxRec);
        return ((numRecords % maxRec)==0) ? n : n+1;
    }
    
    private int getCacheSize() {
        return ((numRecords * record_size) > cacheSize) ? cacheSize / 
record_size : numRecords;
    }
    
    private Comparable getAttribute() throws IOException {
        DbaseFileReader.Row row = reader.readRow();
        Object o = row.read(attributeColumn);
        if (o instanceof Date) {
            //use ms from 1/1/70
            return new Long(((Date)o).getTime());
        }
        return (Comparable)o;
    }
    
    private IndexRecord readRecord(DataInputStream in) throws IOException {
        Comparable obj = null;
        switch (attributeType) {
            case 'N':
            case 'D':
                if (attributeClass.isInstance(new Integer(0))) {
                    obj = new Integer(in.readInt());
                } else {
                    obj = new Long(in.readLong());
                }
                break;
            case 'F':
                obj = new Double(in.readDouble());
                break;
            case 'L':
                obj = new Boolean(in.readBoolean());
                break;
            case 'C':
            default:
                byte[] b = new byte[record_size - 8];
                in.read(b);
                obj = (new String(b, "ISO-8859-1")).trim();
            }
        long id = in.readLong();
        return new IndexRecord(obj, id);
    }
    
    private void write(IndexRecord r) throws IOException {
        try {
            if (r == null)
                return;
            if (writeBuffer == null)
                allocateBuffers();
            if (writeBuffer.remaining() < record_size)
                drain();
            switch (attributeType) {
                case 'N':
                case 'D':
                    Object obj = r.getAttribute();
                    //sometimes DbaseFileReader reads an attribute as Integer, 
even if it's described as Long in the header
                    if (attributeClass.isInstance(new Integer(0))) {
                        int i = (obj instanceof Integer) ? ((Number) 
obj).intValue() : (int) ((Number) obj).longValue();
                        writeBuffer.putInt(i);
                    } else {
                        long l = (obj instanceof Integer) ? (long) ((Number) 
obj).intValue() : ((Number) obj).longValue();
                        writeBuffer.putLong(l);
                    }
                    break;
                case 'F':
                    writeBuffer.putDouble(((Double) 
r.getAttribute()).doubleValue());
                    break;
                case 'L':
                    boolean b = ((Boolean) r.getAttribute()).booleanValue();
                    writeBuffer.put((byte)(b?1:0));
                    break;
                case 'C':
                default:
                    byte[] btemp = 
r.getAttribute().toString().getBytes("ISO-8859-1");
                    byte[] bres = new byte[record_size-8];
                    for (int i = 0; i < bres.length; i++) {
                        bres[i] = (i<btemp.length) ? btemp[i] : (byte)0;
                    }
                    writeBuffer.put(bres);
            }
            writeBuffer.putLong(r.getFeatureID());
        } catch (UnsupportedEncodingException ex) {
            throw new IOException(ex.getMessage());
        }
    }
    
    private void writeHeader() throws IOException {
        ByteBuffer buf = ByteBuffer.allocate(HEADER_SIZE);
        buf.put((byte)attributeType);
        buf.putInt(record_size); //record size in buffer
        buf.putInt(numRecords); //number of records in this index
        buf.flip();
        writeChannel.write(buf, 0);
    }
    
    private void allocateBuffers() throws IOException {
        writeBuffer = ByteBuffer.allocateDirect(HEADER_SIZE+record_size * 1024);
    }
    
    private void drain() throws IOException {
        if (writeBuffer==null)
            return;
        writeBuffer.flip();
        int written = 0;
        while (writeBuffer.remaining() > 0) {
            written += currentChannel.write(writeBuffer, position);
        }
        position += written;
        writeBuffer.flip().limit(writeBuffer.capacity());
    }
    
    private boolean retrieveAttributeInfos() {
        DbaseFileHeader header = reader.getHeader();
        for (int i = 0; i < header.getNumFields(); i++) {
            if (header.getFieldName(i).equals(attribute)) {
                attributeColumn = i;
                attributeClass = header.getFieldClass(i);
                numRecords = header.getNumRecords();
                attributeType = header.getFieldType(i);
                switch (attributeType) {
                    case 'C': //Character
                        record_size = header.getFieldLength(i);
                        break;
                    case 'N': //Numeric
                        if (attributeClass.isInstance(new Integer(0)))
                            record_size = 4;
                        else
                            record_size = 8; //Long and Double are represented 
using 64 bits
                        break;
                    case 'F': //Float
                        record_size = 8;
                        break;
                    case 'D': //Date
                        record_size = 8; //stored in ms from 1/1/70
                        break;
                    case 'L': //Logic
                        record_size = 1; //of course index on boolean feature 
doesn't have any meaning
                        break;
                    default:
                        record_size = header.getFieldLength(i);                 
           
                }
                record_size += 8; //fid index
                return true;
            }
        }
        return false;
    }
    
    private void close() throws IOException {
        try {
            drain();
        } finally {
            if (writeBuffer != null) {
                if (writeBuffer instanceof MappedByteBuffer) {
                    NIOUtilities.clean(writeBuffer);
                }
            }
            if (currentChannel!=null && currentChannel.isOpen()) {
                currentChannel.close();
            }
        }
    }

}
/**
 * Record stored in attribute index file
 * @author Manuele Ventoruzzo
 */
public class IndexRecord implements Comparable {

    private Comparable attribute;
    private long featureID;

    public IndexRecord(Comparable attribute, long featureID) {
        this.attribute = attribute;
        this.featureID = featureID;
    }

    public Object getAttribute() {
        return attribute;
    }

    public long getFeatureID() {
        return featureID;
    }

    public int compareTo(Object o) {
        if (o instanceof IndexRecord) {
            return attribute.compareTo(((IndexRecord) o).getAttribute());
        }
        if (attribute.getClass().isInstance(o)) {
            //compare just attribute with o
            return attribute.compareTo(o);
        }
        throw new ClassCastException("Object " + o.toString() + " is not of 
Record type");
    }

    public String toString() {
        return "(" + attribute.toString() + "," + featureID + ")";
    }
    }
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Geotools-gt2-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/geotools-gt2-users

Reply via email to