⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 indexedfidreader.java

📁 shape file read and write
💻 JAVA
字号:
/*
 *    GeoTools - OpenSource mapping toolkit
 *    http://geotools.org
 *    (C) 2005-2006, GeoTools Project Managment Committee (PMC)
 *
 *    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.
 */
package org.geotools.data.shapefile.indexed;

import static org.geotools.data.shapefile.ShpFileType.FIX;

import java.io.IOException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.util.NoSuchElementException;
import java.util.logging.Logger;

import org.geotools.data.DataUtilities;
import org.geotools.data.FIDReader;
import org.geotools.data.shapefile.FileReader;
import org.geotools.data.shapefile.ShpFiles;
import org.geotools.data.shapefile.StreamLogging;
import org.geotools.data.shapefile.shp.ShapefileReader;
import org.geotools.resources.NIOUtilities;

/**
 * This object reads from a file the fid of a feature in a shapefile.
 * 
 * @author Jesse
 */
public class IndexedFidReader implements FIDReader, FileReader {
    private static final Logger LOGGER = org.geotools.util.logging.Logging
            .getLogger("org.geotools.data.shapefile");
    private ReadableByteChannel readChannel;
    private ByteBuffer buffer;
    private long count;
    private String typeName;
    private boolean done;
    private int removes;
    private int currentShxIndex = -1;
    private RecordNumberTracker reader;
    private long currentId;
    /**
     * move the reader to the recno-th entry in the file.
     * 
     * @param recno
     * @throws IOException
     */
    private long bufferStart = Long.MIN_VALUE;
    StreamLogging streamLogger = new StreamLogging("IndexedFidReader");

    public IndexedFidReader(ShpFiles shpFiles) throws IOException {
        init( shpFiles, shpFiles.getReadChannel(FIX, this) );
    }

    public IndexedFidReader(ShpFiles shpFiles, RecordNumberTracker reader)
            throws IOException {
        this(shpFiles);
        this.reader = reader;

    }

    public IndexedFidReader( ShpFiles shpFiles, ReadableByteChannel in ) throws IOException {
        init(shpFiles, in);
    }

    private void init( ShpFiles shpFiles, ReadableByteChannel in ) throws IOException {
        this.typeName = shpFiles.getTypeName() + ".";
        this.readChannel = in;
        streamLogger.open();
        getHeader(shpFiles);

        buffer = ByteBuffer.allocateDirect(12 * 1024);
        buffer.position(buffer.limit());
    }

    private void getHeader(ShpFiles shpFiles) throws IOException {
        ByteBuffer buffer = ByteBuffer.allocate(IndexedFidWriter.HEADER_SIZE);
        ShapefileReader.fill(buffer, readChannel);

        if (buffer.position() == 0) {
            done = true;
            count = 0;

            return;
        }

        buffer.position(0);

        byte version = buffer.get();

        if (version != 1) {
            throw new IOException(
                    "File is not of a compatible version for this reader or file is corrupt.");
        }

        this.count = buffer.getLong();
        this.removes = buffer.getInt();
        if (removes > getCount() / 2) {
            URL url = shpFiles.acquireRead(FIX, this);
            try {
                DataUtilities.urlToFile(url).deleteOnExit();
            } finally {
                shpFiles.unlockRead(url, this);
            }
        }
    }

    /**
     * Returns the number of Fid Entries in the file.
     * 
     * @return Returns the number of Fid Entries in the file.
     */
    public long getCount() {
        return count;
    }

    /**
     * Returns the number of features that have been removed since the fid index
     * was regenerated.
     * 
     * @return Returns the number of features that have been removed since the
     *         fid index was regenerated.
     */
    public int getRemoves() {
        return removes;
    }

    /**
     * Returns the offset to the location in the SHX file that the fid
     * identifies. This search take logN time.
     * 
     * @param fid
     *                the fid to find.
     * 
     * @return Returns the record number of the record in the SHX file that the
     *         fid identifies. Will return -1 if the fid was not found.
     * 
     * @throws IOException
     * @throws IllegalArgumentException
     *                 DOCUMENT ME!
     */
    public long findFid(String fid) throws IOException {
        try {
            long desired = Long.parseLong(fid
                    .substring(fid.lastIndexOf(".") + 1));

            if ((desired < 0)) {
                return -1;
            }

            if (desired < count) {
                return search(desired, -1, this.count, desired - 1);
            } else {
                return search(desired, -1, this.count, count - 1);
            }
        } catch (NumberFormatException e) {
            LOGGER
                    .warning("Fid is not recognized as a fid for this shapefile: "
                            + typeName);
            return -1;
        }
    }

    /**
     * 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 number of the feature in the shx file.
     * 
     * @throws IOException
     */
    long search(long desired, long minRec, long maxRec, long predictedRec)
            throws IOException {
        if (minRec == maxRec) {
            return -1;
        }

        goTo(predictedRec);
        buffer.limit(IndexedFidWriter.RECORD_SIZE);
        next();
        buffer.limit(buffer.capacity());
        if (currentId == desired) {
            return currentShxIndex;
        }

        if (maxRec - minRec < 10) {
            return search(desired, minRec + 1, maxRec, minRec + 1);
        } else {
            long newOffset = desired - currentId;
            long newPrediction = predictedRec + newOffset;

            if (newPrediction <= minRec) {
                newPrediction = minRec + ((predictedRec - minRec) / 2);
            }

            if (newPrediction >= maxRec) {
                newPrediction = predictedRec + ((maxRec - predictedRec) / 2);
            }

            if (newPrediction == predictedRec) {
                return -1;
            }

            if (newPrediction < predictedRec) {
                return search(desired, minRec, predictedRec, newPrediction);
            } else {
                return search(desired, predictedRec, maxRec, newPrediction);
            }
        }
    }

    public void goTo(long recno) throws IOException {
        assert recno<count;
        if (readChannel instanceof FileChannel) {
            long newPosition = IndexedFidWriter.HEADER_SIZE
                    + (recno * IndexedFidWriter.RECORD_SIZE);
            if (newPosition >= bufferStart + buffer.limit()
                    || newPosition < bufferStart) {
                FileChannel fc = (FileChannel) readChannel;
                fc.position(newPosition);
                buffer.limit(buffer.capacity());
                buffer.position(buffer.limit());
            } else {
                buffer.position((int) (newPosition - bufferStart));
            }
        } else {
            throw new IOException(
                    "Read Channel is not a File Channel so this is not possible.");
        }
    }

    public void close() throws IOException {
        try {
            if (buffer != null) {
                if (buffer instanceof MappedByteBuffer) {
                    NIOUtilities.clean(buffer);
                }
            }
            if (reader != null)
                reader.close();
        } finally {
            readChannel.close();
            streamLogger.close();
        }
    }

    public boolean hasNext() throws IOException {
        if (done) {
            return false;
        }

        if (buffer.position() == buffer.limit()) {
            buffer.position(0);

            FileChannel fc = (FileChannel) readChannel;
            bufferStart = fc.position();
            int read = ShapefileReader.fill(buffer, readChannel);

            if (read != 0) {
                buffer.position(0);
            }
        }

        return buffer.remaining() != 0;
    }

    public String next() throws IOException {
        if (reader != null) {
            goTo(reader.getRecordNumber() - 1);
        }

        if (!hasNext()) {
            throw new NoSuchElementException(
                    "Feature could not be read; a the index may be invalid");
        }

        currentId = buffer.getLong();
        currentShxIndex = buffer.getInt();

        return typeName + currentId;
    }

    /**
     * Returns the record number of the feature in the shx or shp that is
     * identified by the the last fid returned by next().
     * 
     * @return Returns the record number of the feature in the shx or shp that
     *         is identified by the the last fid returned by next().
     * 
     * @throws NoSuchElementException
     *                 DOCUMENT ME!
     */
    public int currentSHXIndex() {
        if (currentShxIndex == -1) {
            throw new NoSuchElementException(
                    "Next must be called before there exists a current element.");
        }

        return currentShxIndex;
    }

    /**
     * Returns the index that is appended to the typename to construct the fid.
     * 
     * @return the index that is appended to the typename to construct the fid.
     */
    public long getCurrentFIDIndex(){
        return currentId;
    }
    
    public String id() {
        return getClass().getName();
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -