GeoTools : Data Reading

Reading data from a data store requires the following steps:

  • get the feature type name of the feature type you want to read by using the getTypeNames() method;
  • get a FeatureSource that allows you to read that feature type;
  • perform a Query on the FeatureSource and get a FeatureResult object;
  • ask for a FeatureReader and iterate over the results.

If that sounds way too complicated, you may ask the DataStore for a FeatureReader directly. But be aware that by doing so you are possibly missing caching and other features that are specific to the FeatureSource and FeatureResult.

A Query object is a wrapper around a Filter that provides more capabilities than simple filtering:

  • select what attributes you want to load by means of the getPropertyNames() method;
  • limit the number of resulting features by means of the getMaxFeatures() method;
  • coordinate system change or override using the CoordinateSystemReproject and CoordinateSystem properties (unfortunately, this is not implemented at the moment).

Other functionalities added by FeatureSource and FeatureResults are:

  • feature modification listeners (FeatureSource);
  • bounds computation and possibly caching (FeatureSource and FeatureResults);
  • direct loading of all the results into a feature collection (FeatureResults)

An example: the shapefile reading tool

Now let's have a look at a simple example. The ShapeReader class, attached to this page, has just a simple main method that:

  • asks the user for a shapefile (and falls back on a shapefile contained in the classpath if none is provided);
// get the shapefile URL by either loading it from the file system
// or from the classpath
URL shapeURL = null;
JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileFilter(new SimpleFileFilter("shp", "Shapefile"));
int result = fileChooser.showOpenDialog(null);

if (result == JFileChooser.APPROVE_OPTION) {
    File f = fileChooser.getSelectedFile();
    shapeURL = f.toURL();
} else {
    shapeURL = getResource("org/geotools/sampleData/statepop.shp");
}
  • creates a shapefile datastore from the URL and gets out the single feature type in this datastore;
  • prints out the feature type's non-geometric attributes name and type as a header;
// get feature results
ShapefileDataStore store = new ShapefileDataStore(shapeURL);
String name = store.getTypeNames()[0];
FeatureSource source = store.getFeatureSource(name);
FeatureResults fsShape = source.getFeatures();

// print out a feature type header and wait for user input
FeatureType ft = source.getSchema();
System.out.println("FID\t");
for (int i = 0; i < ft.getAttributeCount(); i++) {
    AttributeType at = ft.getAttributeType( i );
    if (!Geometry.class.isAssignableFrom(at.getType()))
        System.out.print(at.getType().getName() + "\t");
}
System.out.println();
for (int i = 0; i < ft.getAttributeCount(); i++) {
    AttributeType at = ft.getAttributeType( i );
    if (!Geometry.class.isAssignableFrom(at.getType()))
        System.out.print(at.getName() + "\t");
}
System.out.println();
  • prints out every feature id and non-geometric attributes;
// now print out the feature contents (every non geometric attribute)
FeatureReader reader = fsShape.reader();
while (reader.hasNext()) {
    Feature feature = reader.next();
    System.out.print(feature.getID() + "\t");
    for (int i = 0; i < feature.getNumberOfAttributes(); i++) {
        Object attribute = feature.getAttribute( i );
        if (!(attribute instanceof Geometry))
            System.out.print(attribute + "\t");
    }
    System.out.println();
}
reader.close();
  • and finally prints out every feature id and geometry in wkt format.
// and finally print out every geometry in wkt format
reader = fsShape.reader();
while (reader.hasNext()) {
    Feature feature = reader.next();
    System.out.print(feature.getID() + "\t");
    System.out.println(feature.getDefaultGeometry());
    System.out.println();
}
reader.close();

As you can see, the code makes use of the FeatureReader interface, thus loading only one feature at a time, instead of loading the whole feature collection by using FeatureResults.collection(). This means that the shapefile will be read twice, but it also means that this little program can work with shapefile of any size without encountering any out of memory problems.

Of course, if you are going to process different attributes in different ways, you can always build a Query that makes the datastore load only the attributes that you need. At the time of writing, however, this will not improve shapefile performance. Under the hood, the shapefile data store reads every attribute anyway and casts them to a smaller feature type after the features are in memory (thus, we still have some work to do on Shapefile reading optimization).

Attachments:

ShapeReader.java (application/octet-stream)

Comments:

I am pretty new to GeoTools but was unable to get this sample to work.  The FeatureType class I found (in org.geotools.feature) did not have a getAttributeCount() function.  Any help on reading shapefile attributes would be appriciated.

Jim

jim@nrel.colostate.edu

Posted by pilot11 at Jun 23, 2009 22:13