View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.io;
18  
19  import java.io.BufferedReader;
20  import java.io.IOException;
21  import java.io.Reader;
22  import java.util.Iterator;
23  import java.util.NoSuchElementException;
24  
25  /**
26   * An Iterator over the lines in a <code>Reader</code>.
27   * <p>
28   * <code>LineIterator</code> holds a reference to an open <code>Reader</code>.
29   * When you have finished with the iterator you should close the reader
30   * to free internal resources. This can be done by closing the reader directly,
31   * or by calling the {@link #close()} or {@link #closeQuietly(LineIterator)}
32   * method on the iterator.
33   * <p>
34   * The recommended usage pattern is:
35   * <pre>
36   * LineIterator it = FileUtils.lineIterator(file, "UTF-8");
37   * try {
38   *   while (it.hasNext()) {
39   *     String line = it.nextLine();
40   *     /// do something with line
41   *   }
42   * } finally {
43   *   LineIterator.closeQuietly(iterator);
44   * }
45   * </pre>
46   *
47   * @author Niall Pemberton
48   * @author Stephen Colebourne
49   * @author Sandy McArthur
50   * @version $Id: LineIterator.java 437567 2006-08-28 06:39:07Z bayard $
51   * @since Commons IO 1.2
52   */
53  public class LineIterator implements Iterator {
54  
55      /** The reader that is being read. */
56      private final BufferedReader bufferedReader;
57      /** The current line. */
58      private String cachedLine;
59      /** A flag indicating if the iterator has been fully read. */
60      private boolean finished = false;
61  
62      /**
63       * Constructs an iterator of the lines for a <code>Reader</code>.
64       *
65       * @param reader the <code>Reader</code> to read from, not null
66       * @throws IllegalArgumentException if the reader is null
67       */
68      public LineIterator(final Reader reader) throws IllegalArgumentException {
69          if (reader == null) {
70              throw new IllegalArgumentException("Reader must not be null");
71          }
72          if (reader instanceof BufferedReader) {
73              bufferedReader = (BufferedReader) reader;
74          } else {
75              bufferedReader = new BufferedReader(reader);
76          }
77      }
78  
79      //-----------------------------------------------------------------------
80      /**
81       * Indicates whether the <code>Reader</code> has more lines.
82       * If there is an <code>IOException</code> then {@link #close()} will
83       * be called on this instance.
84       *
85       * @return <code>true</code> if the Reader has more lines
86       * @throws IllegalStateException if an IO exception occurs
87       */
88      public boolean hasNext() {
89          if (cachedLine != null) {
90              return true;
91          } else if (finished) {
92              return false;
93          } else {
94              try {
95                  while (true) {
96                      String line = bufferedReader.readLine();
97                      if (line == null) {
98                          finished = true;
99                          return false;
100                     } else if (isValidLine(line)) {
101                         cachedLine = line;
102                         return true;
103                     }
104                 }
105             } catch(IOException ioe) {
106                 close();
107                 throw new IllegalStateException(ioe.toString());
108             }
109         }
110     }
111 
112     /**
113      * Overridable method to validate each line that is returned.
114      *
115      * @param line  the line that is to be validated
116      * @return true if valid, false to remove from the iterator
117      */
118     protected boolean isValidLine(String line) {
119         return true;
120     }
121 
122     /**
123      * Returns the next line in the wrapped <code>Reader</code>.
124      *
125      * @return the next line from the input
126      * @throws NoSuchElementException if there is no line to return
127      */
128     public Object next() {
129         return nextLine();
130     }
131 
132     /**
133      * Returns the next line in the wrapped <code>Reader</code>.
134      *
135      * @return the next line from the input
136      * @throws NoSuchElementException if there is no line to return
137      */
138     public String nextLine() {
139         if (!hasNext()) {
140             throw new NoSuchElementException("No more lines");
141         }
142         String currentLine = cachedLine;
143         cachedLine = null;
144         return currentLine;        
145     }
146 
147     /**
148      * Closes the underlying <code>Reader</code> quietly.
149      * This method is useful if you only want to process the first few
150      * lines of a larger file. If you do not close the iterator
151      * then the <code>Reader</code> remains open.
152      * This method can safely be called multiple times.
153      */
154     public void close() {
155         finished = true;
156         IOUtils.closeQuietly(bufferedReader);
157         cachedLine = null;
158     }
159 
160     /**
161      * Unsupported.
162      *
163      * @throws UnsupportedOperationException always
164      */
165     public void remove() {
166         throw new UnsupportedOperationException("Remove unsupported on LineIterator");
167     }
168 
169     //-----------------------------------------------------------------------
170     /**
171      * Closes the iterator, handling null and ignoring exceptions.
172      *
173      * @param iterator  the iterator to close
174      */
175     public static void closeQuietly(LineIterator iterator) {
176         if (iterator != null) {
177             iterator.close();
178         }
179     }
180 
181 }