GeoTools : Data Writing

Icon

This page it out dated, for an updated example please see:

Confusing?

Icon

In this section you'll see code like:
Feature f = aWriter.next(); // get a feature
Yes, the writer is also a reader. You read a feature using it, modify it, then send it back to the "disk".

There are three categories of data modifications possible with a DataStore:

  • Add features to a newly created FeatureStore
  • Append features to an existing FeatureStore
  • Update or remove features in a FeatureStore

We'll address each of them in the following sections.

Data modifications

Currently there are two broad ways to achieve adding data to a DataStore in geotools:

  • Use a FeatureWriter
  • Use FeatureStore::addFeatures()

For more details on how to create features, please refer to the Features or How to create a simple FeatureCollection from Scratch.

Creating new data

Writing features to a data store requires the following steps when creating a new data store (shapefile in the example below) from scratch using a FeatureWriter:

  • create all the attribute types for the data store (including at least one geometry attribute type);
  • create a FeatureType from the attribute types;
  • create Features using the FeatureType;
  • create the appropriate data store and create the schema using the newly defined FeatureType;
  • get a FeatureSource (from the data store) and downcast it to a FeatureStore object, this will allow us to get a transaction object;
  • get a FeatureWriter object from the DataStore::getFeatureWriter() method using a transaction;
  • invoke the FeatureWriter::next() method to get a new Feature and then set its attributes;
  • call FeatureWriter::write() to write the new Feature;
  • finally, using the transaction to commit the changes and close the transaction.
    	// feature : type creation 
    	AttributeType geom = AttributeTypeFactory.newAttributeType("the_geom",
    			LineString.class);
    	AttributeType roadWidth = AttributeTypeFactory.newAttributeType(
    			"width", Float.class);
    	FeatureType ftRoad = FeatureTypeFactory.newFeatureType(
    			new AttributeType[] { geom, roadWidth }, "road");
    
    	// feature : instance creation 
    	WKTReader wktReader = new WKTReader();
    	LineString geometry = (LineString) wktReader
    			.read("LINESTRING (0 0, 10 10)");
    	Float width = new Float(10);
    	Feature theRoad = ftRoad.create(new Object[] { geometry, width },
    			"myRoad");
    
    	// datastore creation
    	URL anURL = (new File(URI)).toURL();
    	ShapefileDataStore datastore = new ShapefileDataStore(anURL);
    	datastore.createSchema(ftRoad);
    
    	// file saving
    	FeatureWriter aWriter = datastore.getFeatureWriter("road",
    			((FeatureStore) datastore.getFeatureSource("road"))
    					.getTransaction());
    	Feature aNewFeature = aWriter.next();
    	aNewFeature.setAttributes(new Object[] { geometry, width });
    	aWriter.write();
    	aWriter.close();
    
    _NB : A FeatureSource is a read only source of Features, mostly providing getFeatures(). A FeatureStore is used for transactions - it adds updateFeatures, addFeatures, deleteFeatures, as well as setting and
    getting Transactions. So if you want to modify the source of your features you need to use a FeatureStore. The idea is to have the capabilites be detectable from an instaceof, rather than using metadata._

Using FeatureStore::addFeatures(), the above steps can be modified to:

  • wrap the newly created Features in a FeatureReader object using DataUtilities.reader();
  • invoke the FeatureStore::addFeatures(FeatureReader) method to add the created features;
            // feature : type creation
    	AttributeType geom = AttributeTypeFactory.newAttributeType("the_geom",
    			LineString.class);
    	AttributeType roadWidth = AttributeTypeFactory.newAttributeType(
    			"width", Float.class);
    	FeatureType ftRoad = FeatureTypeFactory.newFeatureType(
    			new AttributeType[] { geom, roadWidth }, "road");
    
    	// feature : instance creation
    	WKTReader wktReader = new WKTReader();
    	LineString geometry = (LineString) wktReader
    			.read("LINESTRING (0 0, 10 10)");
    	Float width = new Float(10);
    	Feature theRoad = ftRoad.create(new Object[] { geometry, width },
    			"myRoad");
    
    	// datastore creation
    	URL anURL = (new File(URI)).toURL();
    	ShapefileDataStore datastore = new ShapefileDataStore(anURL);
    	datastore.createSchema(ftRoad);
    
    	// file saving
    	FeatureStore featureStore = (FeatureStore)(datastore.getFeatureSource("road"));
    	FeatureReader aReader = DataUtilities.reader(new Feature[] {theRoad});
    	featureStore. addFeatures( aReader);
    

This process is quite similar when using MySQL as the data store (please refer to How to add features data into MySQL).

Appending to existing data

Writing to data store requires the following steps when appending features to an existing DataStore (shapefile in the example below), using a FeatureWriter.

  • create the appropriate data store and get the feature type name by using the getTypeNames method;
  • get a FeatureSource and downcast it to a FeatureStore object, this will allow us to get a transaction object to properly lock features during writes;
  • get a FeatureWriter object from the DataStore::getFeatureWriterAppend() method using a transaction;
  • invoke the FeatureWriter::next() method to get a new Feature and then set its attributes, this way, we don't have to manage the unique attribute FID;
  • call FeatureWriter::write() to write the new Feature;
  • finally, using the transaction to commit the changes and then close the transaction to free up any locks.
// the follow code append features to the DataStore
FeatureWriter fw = newShapefileDataStore.getFeatureWriterAppend(featureTypeName, transaction);
Feature f = fw.next();
f.setAttributes(new Object[] { geometry, att1, att2, ... });
fw.write();
fw.close();

Example :

	// feature : attributes creation
	WKTReader wktReader = new WKTReader();
	LineString geometry = (LineString) wktReader
			.read("LINESTRING (10 10, 20 20)");
	Float width = new Float(10);

	//getting the feature
	URL anURL = (new File(URI)).toURL();
	ShapefileDataStore datastore = new ShapefileDataStore(anURL);
	String featureName = datastore.getTypeNames()[0]; //road"
	FeatureSource source = datastore.getFeatureSource(featureName);

	// appending feature
	FeatureWriter aWriter = datastore.getFeatureWriterAppend(featureName,
			((FeatureStore) source).getTransaction());

	// get a new feature (empty slot) by calling FeatureWriter::next() again
	Feature f = aWriter.next();
	f.setAttributes(new Object[] { geometry, width });
	aWriter.write();
	aWriter.close();

Using FeatureStore::addFeatures(), the above steps can be modified to:

  • Create the new Features;
  • wrap the new Features in a FeatureReader using DataUtilities.reader();
  • Add the new features to the FeatureStore with FeatureStore::addFeatures(reader);
// the following code append features to a DataStore
FeatureReader reader = DataUtilities.reader(new Feature[] { newFeature1, newFeature2, ... } );
newFeatureStore.addFeatures(reader);

Example :

	// feature : type creation
	AttributeType geom = AttributeTypeFactory.newAttributeType("the_geom",
			LineString.class);
	AttributeType roadWidth = AttributeTypeFactory.newAttributeType(
			"width", Float.class);
	FeatureType ftRoad = FeatureTypeFactory.newFeatureType(
			new AttributeType[] { geom, roadWidth }, "road");

	// feature : instance attribute creation
	WKTReader wktReader = new WKTReader();
	LineString geometry = (LineString) wktReader
			.read("LINESTRING (10 10, 20 20)");
	Float width = new Float(10);
	Feature theRoad = ftRoad.create(new Object[] { geometry, width },
			"myRoad2");

	// getting the feature
	URL anURL = (new File(URI)).toURL();
	ShapefileDataStore datastore = new ShapefileDataStore(anURL);
	String featureName = datastore.getTypeNames()[0]; // road
	FeatureSource source = datastore.getFeatureSource(featureName);

	// appending feature, this will automatically append to the end of shapefile
	FeatureStore featureStore = (FeatureStore) (datastore
			.getFeatureSource("road"));
	FeatureReader aReader = DataUtilities.reader(new Feature[] { theRoad });
	featureStore.addFeatures(aReader);

Updating or removing data

To update/remove features, use the above steps with a Filter object to query the desired features to make modifications on.

Example:

	// feature : type creation
	AttributeType geom = AttributeTypeFactory.newAttributeType("the_geom",
			LineString.class);
	AttributeType roadWidth = AttributeTypeFactory.newAttributeType(
			"width", Float.class);
	FeatureType ftRoad = FeatureTypeFactory.newFeatureType(
			new AttributeType[] { geom, roadWidth }, "road");
		
	// build a filter on an attribute 'DI' between 0.0 and 11.0
	FilterFactory ff = FilterFactory.createFilterFactory();
	LiteralExpression literal0 = ff.createLiteralExpression(0.0);
	LiteralExpression literal11 = ff.createLiteralExpression(11.0);
	AttributeExpression diExpression = ff.createAttributeExpression(ftRoad, "DI");
	BetweenFilter betweenFilter = ff.createBetweenFilter();
	betweenFilter.addLeftValue(literal0);
	betweenFilter.addMiddleValue(diExpression);
	betweenFilter.addRightValue(literal11);

	// feature : instance attribute creation
	Float width = new Float(20);

	// getting the shapefile
	URL anURL = (new File(URI)).toURL();
	ShapefileDataStore datastore = new ShapefileDataStore(anURL);
	String featureName = datastore.getTypeNames()[0]; // road for this example
		
	// modifying feature
	FeatureStore featureStore = (FeatureStore) (datastore
			.getFeatureSource(featureName));

	featureStore.modifyFeatures(roadWidth,width,betweenFilter);

	// removing feature
	featureStore.removeFeatures(betweenFilter);