001: /*
002: * ShapeReader.java
003: *
004: * Created on June 27, 2002, 2:49 PM
005: */
006: /*
007: * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
008: * for visualizing and manipulating spatial features with geometry and attributes.
009: *
010: * Copyright (C) 2003 Vivid Solutions
011: *
012: * This program is free software; you can redistribute it and/or
013: * modify it under the terms of the GNU General Public License
014: * as published by the Free Software Foundation; either version 2
015: * of the License, or (at your option) any later version.
016: *
017: * This program is distributed in the hope that it will be useful,
018: * but WITHOUT ANY WARRANTY; without even the implied warranty of
019: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
020: * GNU General Public License for more details.
021: *
022: * You should have received a copy of the GNU General Public License
023: * along with this program; if not, write to the Free Software
024: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
025: *
026: * For more information, contact:
027: *
028: * Vivid Solutions
029: * Suite #1A
030: * 2328 Government Street
031: * Victoria BC V8T 5G5
032: * Canada
033: *
034: * (250)385-6040
035: * www.vividsolutions.com
036: */
037: package com.vividsolutions.jump.io;
038:
039: import com.vividsolutions.jts.geom.*;
040:
041: import com.vividsolutions.jump.I18N;
042: import com.vividsolutions.jump.feature.*;
043:
044: import org.geotools.dbffile.DbfFile;
045:
046: import org.geotools.shapefile.Shapefile;
047:
048: import java.io.*;
049:
050: /**
051: * ShapefileReader is a {@link JUMPReader} specialized to read Shapefiles.
052: *
053: * <p>
054: * DataProperties for the JUMPReader load(DataProperties) interface:<br><br>
055: * </p>
056: *
057: * <p>
058: * <table border='1' cellspacing='0' cellpadding='4'>
059: * <tr>
060: * <th>Parameter</th><th>Meaning</th>
061: * </tr>
062: * <tr>
063: * <td>InputFile or DefaultValue</td>
064: * <td>File name for the input .shp file</td>
065: * </tr>
066: * <tr>
067: * <td colspan='2'>
068: * NOTE: The input .dbf is assumed to be 'beside' (in the same
069: * directory) as the .shp file.
070: * </td>
071: * </tr>
072:
073: * <tr>
074: * <td>CompressedFile</td>
075: * <td>File name (.zip NOT a .gz) with a .shp and .dbf file inside</td>
076: * </tr>
077: *
078: * <tr>
079: * <td colspan='2'>
080: * Uses a modified version of geotools to do the .dbf and .shp
081: * file reading. If you are reading from a .zip file, the dbf
082: * file will be copied to your temp directory and deleted
083: * after being read.
084: * </td>
085: * </tr>
086: * </table>
087:
088: */
089: public class ShapefileReader implements JUMPReader {
090: private File delete_this _tmp_dbf = null;
091:
092: public static final String FILE_PROPERTY_KEY = "File";
093: public static final String DEFAULT_VALUE_PROPERTY_KEY = "DefaultValue";
094: public static final String COMPRESSED_FILE_PROPERTY_KEY = "CompressedFile";
095:
096: /** Creates new ShapeReader */
097: public ShapefileReader() {
098: }
099:
100: /**
101: * Main method to read a shapefile. Most of the work is done in the org.geotools.* package.
102: *
103: *@param dp 'InputFile' or 'DefaultValue' to specify output .shp file.
104: *
105: */
106: public FeatureCollection read(DriverProperties dp)
107: throws IllegalParametersException, Exception {
108:
109: String shpfileName = dp.getProperty(FILE_PROPERTY_KEY);
110:
111: if (shpfileName == null) {
112: shpfileName = dp.getProperty(DEFAULT_VALUE_PROPERTY_KEY);
113: }
114:
115: if (shpfileName == null) {
116: throw new IllegalParametersException(
117: I18N
118: .get("io.ShapefileReader.no-file-property-specified"));
119: }
120:
121: int loc = shpfileName.lastIndexOf(File.separatorChar);
122: String path = shpfileName.substring(0, loc + 1); // ie. "/data1/hills.shp" -> "/data1/"
123: String fname = shpfileName.substring(loc + 1); // ie. "/data1/hills.shp" -> "hills.shp"
124:
125: loc = fname.lastIndexOf(".");
126:
127: if (loc == -1) {
128: throw new IllegalParametersException(I18N
129: .get("io.ShapefileReader.filename-must-end-in-shp"));
130: }
131:
132: String fnameWithoutExtention = fname.substring(0, loc); // ie. "hills.shp" -> "hills"
133: String dbfFileName = path + fnameWithoutExtention + ".dbf";
134:
135: //okay, have .shp and .dbf file paths, lets start
136: // install Shapefile and DbfFile
137: Shapefile myshape = getShapefile(shpfileName, dp
138: .getProperty(COMPRESSED_FILE_PROPERTY_KEY));
139: DbfFile mydbf = getDbfFile(dbfFileName, dp
140: .getProperty(COMPRESSED_FILE_PROPERTY_KEY));
141: GeometryFactory factory = new GeometryFactory();
142: GeometryCollection collection = myshape.read(factory);
143: FeatureSchema fs = new FeatureSchema();
144:
145: // fill in schema
146: fs.addAttribute("GEOMETRY", AttributeType.GEOMETRY);
147:
148: FeatureCollection featureCollection = null;
149:
150: if (mydbf == null) {
151: // handle shapefiles without dbf files.
152: featureCollection = new FeatureDataset(fs);
153:
154: int numGeometries = collection.getNumGeometries();
155:
156: for (int x = 0; x < numGeometries; x++) {
157: Feature feature = new BasicFeature(fs);
158: Geometry geo = collection.getGeometryN(x);
159:
160: feature.setGeometry(geo);
161: featureCollection.add(feature);
162: }
163: } else {
164: // There is a DBF file so we have to associate the attributes in
165: // the DBF file with the features.
166: int numfields = mydbf.getNumFields();
167:
168: for (int j = 0; j < numfields; j++) {
169: AttributeType type = AttributeType
170: .toAttributeType(mydbf.getFieldType(j));
171: fs.addAttribute(mydbf.getFieldName(j), type);
172: }
173:
174: featureCollection = new FeatureDataset(fs);
175:
176: for (int x = 0; x < mydbf.getLastRec(); x++) {
177: Feature feature = new BasicFeature(fs);
178: Geometry geo = collection.getGeometryN(x);
179: StringBuffer s = mydbf.GetDbfRec(x);
180:
181: for (int y = 0; y < numfields; y++) {
182: feature.setAttribute(y + 1, mydbf
183: .ParseRecordColumn(s, y));
184: }
185:
186: feature.setGeometry(geo);
187: featureCollection.add(feature);
188: }
189:
190: mydbf.close();
191: deleteTmpDbf(); // delete dbf file if it was decompressed
192: }
193: //System.gc();
194:
195: return featureCollection;
196: }
197:
198: protected Shapefile getShapefile(String shpfileName,
199: String compressedFname) throws Exception {
200: InputStream in = CompressedFile.openFile(shpfileName,
201: compressedFname);
202: Shapefile myshape = new Shapefile(in);
203: return myshape;
204: }
205:
206: protected DbfFile getDbfFile(String dbfFileName,
207: String compressedFname) throws Exception {
208:
209: DbfFile mydbf = null;
210:
211: if ((compressedFname != null) && (compressedFname.length() > 0)) {
212: byte[] b = new byte[16000];
213: int len;
214: boolean keepGoing = true;
215:
216: // copy the file then use that copy
217: File file = File.createTempFile("dbf", ".dbf");
218: FileOutputStream out = new FileOutputStream(file);
219:
220: InputStream in = CompressedFile.openFile(dbfFileName,
221: compressedFname);
222:
223: while (keepGoing) {
224: len = in.read(b);
225:
226: if (len > 0) {
227: out.write(b, 0, len);
228: }
229:
230: keepGoing = (len != -1);
231: }
232:
233: in.close();
234: out.close();
235:
236: mydbf = new DbfFile(file.toString());
237: delete_this _tmp_dbf = file; // to be deleted later on
238: } else {
239: File dbfFile = new File(dbfFileName);
240:
241: if (dbfFile.exists()) {
242: mydbf = new DbfFile(dbfFileName);
243: }
244: }
245:
246: return mydbf;
247: }
248:
249: private void deleteTmpDbf() {
250: if (delete_this_tmp_dbf != null) {
251: delete_this_tmp_dbf.delete();
252: delete_this_tmp_dbf = null;
253: }
254: }
255: }
|