Wow,  Thanks for this contribution Manuele.  I will try to apply it  
later today.  (I'm the shapefile module maintainer BTW :).)  I'm going  
to put on trunk.  I hope that is ok.

Jesse
Le 7-Feb-08 à 12:38 AM, Manuele Ventoruzzo a écrit :

> 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


-------------------------------------------------------------------------
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