KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > anupam > csv > CSVReader


1 /*
2  * CSVReader.java
3  *
4  * Copyright (C) 2005 Anupam Sengupta (anupamsg@users.sourceforge.net)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * Version $Revision: 1.3 $
21  */

22 package net.sf.anupam.csv;
23
24 import com.Ostermiller.util.CSVParse;
25 import com.Ostermiller.util.ExcelCSVParser;
26 import org.apache.commons.collections.CollectionUtils;
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29
30 import java.io.IOException JavaDoc;
31 import java.io.Reader JavaDoc;
32 import java.util.ArrayList JavaDoc;
33 import java.util.Iterator JavaDoc;
34 import java.util.List JavaDoc;
35 import java.util.NoSuchElementException JavaDoc;
36
37 /**
38  * Reads a CSV file and parses the individual fields for each CSV record in the
39  * file. The default delimiter is assumed to be the <code>,</code> (comma).
40  * <p/>
41  * <p/>
42  * The class uses the CSV Parser engines from <a
43  * HREF="http://ostermiller.org/utils/" target="_blank">Steven Ostermiller's
44  * site</a>.
45  * </p>
46  *
47  * @author Anupam Sengupta
48  * @version $Revision: 1.3 $
49  * @see com.Ostermiller.util.CSVParse
50  * @since 1.5
51  */

52 class CSVReader implements Iterable JavaDoc<List JavaDoc<String JavaDoc>> {
53
54     /**
55      * Logger to use.
56      */

57     private static final Log LOG = LogFactory.getLog(CSVReader.class);
58
59     /**
60      * The CSV parser engine.
61      */

62     private CSVParse parser;
63
64     /**
65      * Flag which indicates whether the reader has read all the records.
66      */

67     private boolean readingComplete;
68
69     /**
70      * Flag which indicates whether the CSV file has a header row.
71      */

72     private boolean headerPresent;
73
74     /**
75      * Constructor which accepts a reader on the CSV stream to parse. The
76      * presence of a CSV header row is also specified. If present, the header
77      * row will be skipped.
78      *
79      * @param csvReader the CSV stream reader from which to parse
80      * @param headerPresent indicates whether the CSV stream has a header record
81      */

82     public CSVReader(final Reader JavaDoc csvReader, final boolean headerPresent) {
83         super();
84         this.headerPresent = headerPresent;
85
86         parser = new ExcelCSVParser(csvReader);
87
88     }
89
90     /**
91      * Releases all system resources.
92      */

93     public void close() {
94         try {
95             if (parser != null) {
96                 parser.close();
97                 LOG.debug("Closed the CSV Reader");
98             }
99         } catch (final IOException JavaDoc e) {
100             // Do nothing
101
} finally {
102             parser = null;
103         }
104     }
105
106     /**
107      * Finalizes this CSV reader and closes the IO connections.
108      *
109      * @throws Throwable thrown if the finalization fails.
110      * @see Object#finalize()
111      */

112     @Override JavaDoc
113     protected void finalize() throws Throwable JavaDoc {
114         super.finalize();
115         close();
116     }
117
118     /**
119      * Returns an iterator over the parsed lines. The iterator returns a list of
120      * the CSV field values as a single value over each iteration.
121      *
122      * @return an iterator over the lines.
123      */

124     public Iterator JavaDoc<List JavaDoc<String JavaDoc>> iterator() {
125         return new LineIterator();
126     }
127
128     // ~ Inner Classes
129
// ----------------------------------------------------------
130

131     /**
132      * Inner iterator class to provide the Iterable interface to the reader.
133      */

134     private class LineIterator implements Iterator JavaDoc<List JavaDoc<String JavaDoc>> {
135         // ~ Methods
136
// ------------------------------------------------------------
137

138         /**
139          * The parsed CSV field values.
140          */

141         private String JavaDoc[] parsedValues;
142
143         /**
144          * Flag indicating whether the previous line was read.
145          */

146         private boolean haveReadPreviousLine;
147
148         /**
149          * Default Constructor.
150          */

151         public LineIterator() {
152             super();
153             if (isHeaderPresent()) {
154                 readOneLine();
155             }
156         }
157
158         /**
159          * Returns <code>true</code> if there is at least one more parsed CSV line.
160          *
161          * @return <code>true></code> if there is at least one more parsed line
162          * @see java.util.Iterator#hasNext()
163          */

164         public boolean hasNext() {
165             if (isReadingComplete()) {
166                 return false;
167             }
168
169             if (!haveReadPreviousLine) {
170                 readOneLine();
171                 haveReadPreviousLine = true;
172             }
173             return !isReadingComplete();
174         }
175
176         /**
177          * Returns a list of the CSV field values for the current line.
178          *
179          * @return the next list of parsed CSV field values
180          * @see java.util.Iterator#next()
181          */

182         public List JavaDoc<String JavaDoc> next() {
183
184             if (!haveReadPreviousLine) {
185                 readOneLine();
186             } else {
187                 haveReadPreviousLine = false;
188             }
189
190             if (isReadingComplete()) {
191                 throw new NoSuchElementException JavaDoc();
192             }
193
194             final List JavaDoc<String JavaDoc> valueList = new ArrayList JavaDoc<String JavaDoc>(
195                     parsedValues.length);
196             CollectionUtils.addAll(valueList, parsedValues);
197
198             return valueList;
199
200         }
201
202         /**
203          * Reads one CSV line using the CSV parser engine and stores the parsed
204          * line fields.
205          */

206         private void readOneLine() {
207             try {
208                 parsedValues = getParser().getLine();
209                 if (parsedValues == null) {
210                     readingIsComplete();
211                 }
212             } catch (final IOException JavaDoc e) {
213                 LOG.warn("Error in reading a line from the CSV stream ", e);
214                 readingIsComplete();
215             }
216
217         }
218
219         /**
220          * This method is not supported.
221          *
222          * @see java.util.Iterator#remove()
223          */

224         public void remove() {
225             LOG
226                     .debug("Invalid call to the unsupported remove() method on the iterator");
227             throw new UnsupportedOperationException JavaDoc(
228                     "This method is not supported");
229         }
230     }
231
232     /**
233      * Indicates whether the header row is present or not.
234      *
235      * @return Returns <code>true</code> if the header row is present
236      */

237     public boolean isHeaderPresent() {
238         return this.headerPresent;
239     }
240
241     /**
242      * Indicates whether the reader has read all CSV lines.
243      *
244      * @return Returns <code>true</code> if all CSV lines have been read
245      */

246     public boolean isReadingComplete() {
247         return this.readingComplete;
248     }
249
250     /**
251      * Sets the flag to denote that all lines have been read.
252      */

253     protected void readingIsComplete() {
254         this.readingComplete = true;
255     }
256
257     /**
258      * Returns the internal CSV parser engine instance for this reader.
259      *
260      * @return Returns the parser instance
261      */

262     protected CSVParse getParser() {
263         return this.parser;
264     }
265 }
266
Popular Tags