📄 indexedshapefiledatastore.java
字号:
/*
* GeoTools - OpenSource mapping toolkit
* http://geotools.org
* (C) 2003-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.DBF;
import static org.geotools.data.shapefile.ShpFileType.FIX;
import static org.geotools.data.shapefile.ShpFileType.QIX;
import static org.geotools.data.shapefile.ShpFileType.SHP;
import static org.geotools.data.shapefile.ShpFileType.SHX;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.nio.channels.ReadableByteChannel;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import org.geotools.data.DataSourceException;
import org.geotools.data.DataUtilities;
import org.geotools.data.EmptyFeatureReader;
import org.geotools.data.FIDReader;
import org.geotools.data.FeatureReader;
import org.geotools.data.FeatureWriter;
import org.geotools.data.InProcessLockingManager;
import org.geotools.data.Query;
import org.geotools.data.Transaction;
import org.geotools.data.TransactionStateDiff;
import org.geotools.data.shapefile.FileWriter;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.shapefile.ShapefileDataStoreFactory;
import org.geotools.data.shapefile.ShpFileType;
import org.geotools.data.shapefile.dbf.DbaseFileReader;
import org.geotools.data.shapefile.dbf.IndexedDbaseFileReader;
import org.geotools.data.shapefile.shp.IndexFile;
import org.geotools.data.shapefile.shp.ShapefileReader;
import org.geotools.data.shapefile.shp.ShapefileReader.Record;
import org.geotools.feature.SchemaException;
import org.geotools.feature.visitor.IdCollectorFilterVisitor;
import org.geotools.filter.FilterAttributeExtractor;
import org.geotools.filter.visitor.ExtractBoundsFilterVisitor;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.index.CloseableCollection;
import org.geotools.index.Data;
import org.geotools.index.DataDefinition;
import org.geotools.index.LockTimeoutException;
import org.geotools.index.TreeException;
import org.geotools.index.quadtree.QuadTree;
import org.geotools.index.quadtree.StoreException;
import org.geotools.index.quadtree.fs.FileSystemIndexStore;
import org.geotools.index.rtree.RTree;
import org.geotools.util.NullProgressListener;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.filter.Filter;
import org.opengis.filter.Id;
import com.vividsolutions.jts.geom.Envelope;
/**
* A DataStore implementation which allows reading and writing from Shapefiles.
*
* @author Ian Schneider
* @author Tommaso Nolli
* @author jesse eichar
*
* @source $URL:
* http://svn.geotools.org/geotools/branches/constantTimeFid/src/org/geotools/data/shapefile/indexed/IndexedShapefileDataStore.java $
*/
public class IndexedShapefileDataStore extends ShapefileDataStore implements
FileWriter {
IndexType treeType;
final boolean useIndex;
private RTree rtree;
int maxDepth;
/**
* Creates a new instance of ShapefileDataStore.
*
* @param url
* The URL of the shp file to use for this DataSource.
*/
public IndexedShapefileDataStore(URL url)
throws java.net.MalformedURLException {
this(url, null, false, true, IndexType.QIX);
}
/**
* Creates a new instance of ShapefileDataStore.
*
* @param url
* The URL of the shp file to use for this DataSource.
* @param namespace
* DOCUMENT ME!
*/
public IndexedShapefileDataStore(URL url, URI namespace)
throws java.net.MalformedURLException {
this(url, namespace, false, true, IndexType.QIX);
}
/**
* Creates a new instance of ShapefileDataStore.
*
* @param url
* The URL of the shp file to use for this DataSource.
* @param useMemoryMappedBuffer
* enable/disable memory mapping of files
* @param createIndex
* enable/disable automatic index creation if needed
*/
public IndexedShapefileDataStore(URL url, boolean useMemoryMappedBuffer,
boolean createIndex) throws java.net.MalformedURLException {
this(url, null, useMemoryMappedBuffer, createIndex, IndexType.QIX);
}
/**
* Creates a new instance of ShapefileDataStore.
*
* @param url
* The URL of the shp file to use for this DataSource.
* @param namespace
* DOCUMENT ME!
* @param useMemoryMappedBuffer
* enable/disable memory mapping of files
* @param createIndex
* enable/disable automatic index creation if needed
* @param treeType
* The type of index to use
*
*/
public IndexedShapefileDataStore(URL url, URI namespace,
boolean useMemoryMappedBuffer, boolean createIndex,
IndexType treeType) throws MalformedURLException {
this(url, namespace, useMemoryMappedBuffer, createIndex, treeType,
DEFAULT_STRING_CHARSET);
}
/**
* Creates a new instance of ShapefileDataStore.
*
* @param url
* The URL of the shp file to use for this DataSource.
* @param namespace
* DOCUMENT ME!
* @param useMemoryMappedBuffer
* enable/disable memory mapping of files
* @param createIndex
* enable/disable automatic index creation if needed
* @param treeType
* The type of index used
* @param dbfCharset
* {@link Charset} used to decode strings from the DBF
*
* @throws NullPointerException
* DOCUMENT ME!
* @throws .
*/
public IndexedShapefileDataStore(URL url, URI namespace,
boolean useMemoryMappedBuffer, boolean createIndex,
IndexType treeType, Charset dbfCharset)
throws java.net.MalformedURLException {
super(url, namespace, useMemoryMappedBuffer, dbfCharset);
this.treeType = treeType;
this.useIndex = treeType != IndexType.NONE;
maxDepth = -1;
try {
if (shpFiles.isLocal() && createIndex
&& needsGeneration(treeType.shpFileType)) {
createSpatialIndex();
}
} catch (IOException e) {
this.treeType = IndexType.NONE;
ShapefileDataStoreFactory.LOGGER.log(Level.SEVERE, e
.getLocalizedMessage());
}
try {
if (shpFiles.isLocal() && needsGeneration(FIX)) {
generateFidIndex();
}
} catch (IOException e) {
ShapefileDataStoreFactory.LOGGER.log(Level.SEVERE, e
.getLocalizedMessage());
}
}
/**
* Forces the spatial index to be created
*/
public void createSpatialIndex() throws IOException {
buildQuadTree(maxDepth);
}
protected void finalize() throws Throwable {
if (rtree != null) {
try {
rtree.close();
} catch (Exception e) {
e.printStackTrace();
LOGGER
.severe("org.geotools.data.shapefile.indexed.IndexedShapeFileDataStore#finalize(): Error closing rtree. "
+ e.getLocalizedMessage());
}
}
}
protected Filter getUnsupportedFilter(String typeName, Filter filter) {
if (filter instanceof Id && isLocal() && shpFiles.exists(FIX))
return Filter.INCLUDE;
return filter;
}
public FeatureWriter<SimpleFeatureType, SimpleFeature> getFeatureWriterAppend(String typeName,
Transaction transaction) throws IOException {
if (transaction == null) {
throw new NullPointerException(
"getFeatureWriter requires Transaction: "
+ "did you mean to use Transaction.AUTO_COMMIT?");
}
FeatureWriter<SimpleFeatureType, SimpleFeature> writer;
if (transaction == Transaction.AUTO_COMMIT) {
return super.getFeatureWriterAppend(typeName, transaction);
} else {
writer = state(transaction).writer(typeName, Filter.EXCLUDE);
}
if (getLockingManager() != null) {
// subclass has not provided locking so we will
// fake it with InProcess locks
writer = ((InProcessLockingManager) getLockingManager())
.checkedWriter(writer, transaction);
}
while (writer.hasNext())
writer.next();
return writer;
}
/**
* This method is identical to the super class WHY?
*/
protected TransactionStateDiff state(Transaction transaction) {
synchronized (transaction) {
TransactionStateDiff state = (TransactionStateDiff) transaction
.getState(this);
if (state == null) {
state = new TransactionStateDiff(this);
transaction.putState(this, state);
}
return state;
}
}
/**
* Use the spatial index if available and adds a small optimization: if no
* attributes are going to be read, don't uselessly open and read the dbf
* file.
*
* @see org.geotools.data.AbstractDataStore#getFeatureReader(java.lang.String,
* org.geotools.data.Query)
*/
protected FeatureReader<SimpleFeatureType, SimpleFeature> getFeatureReader(String typeName, Query query)
throws IOException {
if (query.getFilter() == Filter.EXCLUDE)
return new EmptyFeatureReader<SimpleFeatureType, SimpleFeature>(getSchema());
String[] propertyNames = query.getPropertyNames() == null ? new String[0]
: query.getPropertyNames();
String defaultGeomName = schema.getDefaultGeometry().getLocalName();
FilterAttributeExtractor fae = new FilterAttributeExtractor();
query.getFilter().accept(fae, null);
Set attributes = new HashSet(Arrays.asList(propertyNames));
attributes.addAll(fae.getAttributeNameSet());
SimpleFeatureType newSchema = schema;
boolean readDbf = true;
boolean readGeometry = true;
propertyNames = (String[]) attributes.toArray(new String[attributes
.size()]);
try {
if (((query.getPropertyNames() != null)
&& (propertyNames.length == 1) && propertyNames[0]
.equals(defaultGeomName))) {
readDbf = false;
newSchema = DataUtilities.createSubType(schema, propertyNames);
} else if ((query.getPropertyNames() != null)
&& (propertyNames.length == 0)) {
readDbf = false;
readGeometry = false;
newSchema = DataUtilities.createSubType(schema, propertyNames);
}
return createFeatureReader(typeName, getAttributesReader(readDbf,
readGeometry, query.getFilter()), newSchema);
} catch (SchemaException se) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -