/* GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2010-2014, Open Source Geospatial Foundation (OSGeo) * * This file is hereby placed into the Public Domain. This means anyone is * free to do whatever they wish with this file. Use it well and enjoy! */ package org.geotools.tutorial.csv2; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.util.NoSuchElementException; import org.geotools.data.DataUtilities; import org.geotools.data.FeatureWriter; import org.geotools.data.Query; import org.geotools.data.store.ContentState; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.opengis.feature.Property; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import com.csvreader.CsvReader; import com.csvreader.CsvWriter; import com.vividsolutions.jts.geom.Point; /** * Iterator supporting writing of feature content. * * @author Jody Garnett (Boundless) * @author Lee Breisacher */ public class CSVFeatureWriter implements FeatureWriter<SimpleFeatureType, SimpleFeature> { /** State of current transaction */ private ContentState state; /** Delegate handing reading of original file */ private CSVFeatureReader delegate; /** Temporary file used to stage output */ private File temp; /** CsvWriter used for temp file output */ private CsvWriter csvWriter; /** Current feature available for modification, may be null if feature removed */ private SimpleFeature currentFeature; /** Flag indicating we have reached the end of the file */ private boolean appending = false; /** Row count used to generate FeatureId when appending */ int nextRow = 0; // header end // constructor start public CSVFeatureWriter(ContentState state, Query query) throws IOException { this.state = state; String typeName = query.getTypeName(); File file = ((CSVDataStore) state.getEntry().getDataStore()).file; File directory = file.getParentFile(); this.temp = File.createTempFile(typeName + System.currentTimeMillis(), "csv", directory); this.csvWriter = new CsvWriter(new FileWriter(this.temp), ','); this.delegate = new CSVFeatureReader(state,query); this.csvWriter.writeRecord(delegate.reader.getHeaders()); } // constructor end // featureType start @Override public SimpleFeatureType getFeatureType() { return state.getFeatureType(); } // featureType end // hasNext start @Override public boolean hasNext() throws IOException { if( csvWriter == null ){ return false; } if (this.appending) { return false; // reader has no more contents } return delegate.hasNext(); } // hasNext end // next start @Override public SimpleFeature next() throws IOException, IllegalArgumentException, NoSuchElementException { if( csvWriter == null ){ throw new IOException("FeatureWriter has been closed"); } if (this.currentFeature != null) { this.write(); // the previous one was not written, so do it now. } try { if( !appending ){ if( delegate.reader != null && delegate.hasNext() ){ this.currentFeature = delegate.next(); return this.currentFeature; } else { this.appending = true; } } SimpleFeatureType featureType = state.getFeatureType(); String fid = featureType.getTypeName()+"."+nextRow; Object values[] = DataUtilities.defaultValues( featureType ); this.currentFeature = SimpleFeatureBuilder.build( featureType, values, fid ); return this.currentFeature; } catch (IllegalArgumentException invalid ){ throw new IOException("Unable to create feature:"+invalid.getMessage(),invalid); } } // next end // remove start /** * Mark our {@link #currentFeature} feature as null, it will be skipped when written effectively removing it. */ public void remove() throws IOException { this.currentFeature = null; // just mark it done which means it will not get written out. } // remove end // write start public void write() throws IOException { if (this.currentFeature == null) { return; // current feature has been deleted } for (Property property : currentFeature.getProperties()) { Object value = property.getValue(); if (value == null) { this.csvWriter.write(""); } else if (value instanceof Point) { Point point = (Point) value; this.csvWriter.write(Double.toString(point.getX())); this.csvWriter.write(Double.toString(point.getY())); } else { String txt = value.toString(); this.csvWriter.write(txt); } } this.csvWriter.endRecord(); nextRow++; this.currentFeature = null; // indicate that it has been written } // write end // close start @Override public void close() throws IOException { if( csvWriter == null ){ throw new IOException("Writer alread closed"); } if (this.currentFeature != null) { this.write(); // the previous one was not written, so do it now. } // Step 1: Write out remaining contents (if applicable) while (hasNext()) { next(); write(); } csvWriter.close(); csvWriter = null; if( delegate != null ){ this.delegate.close(); this.delegate = null; } // Step 2: Replace file contents File file = ((CSVDataStore) state.getEntry().getDataStore()).file; Files.copy(temp.toPath(), file.toPath(), StandardCopyOption.REPLACE_EXISTING ); } // close end }