Wanted to create an easy interface for reading lines from a stream. It should take care of all the annoying Java IO nitty-gritty for me and I wanted to use it simply by throwing it into a for loop.
Found some pieces of code here and there, added some of my own and ended up with a LineReader
class. Works as far as I can see, but let me know if you test it out and you find any bugs :p
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | import java.io.BufferedReader; import java.io.Closeable; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.NoSuchElementException; /** * Represents the lines found in an {@link InputStream}. The lines are read * one at a time using {@link BufferedReader#readLine()} and may be streamed * through an iterator or returned all at once. * * <p>This class does not handle any concurrency issues. * * <p>The stream is closed automatically when the for loop is done :) * * <pre>{@code * for(String line : new LineReader(stream)) * // ... * }</pre> * * <p>An {@link IllegalStateException} will be thrown if any {@link IOException}s * occur when reading or closing the stream. * * @author Torleif Berger * @license http://creativecommons.org/licenses/by/3.0/ * @see http://www.geekality.net/?p=1614 */ public class LineReader implements Iterable<String>, Closeable { private BufferedReader reader; /** * Creates a new {@link LineReader}. * * <p>Uses a {@link FileReader} to read the file. * * @param file Path to file with lines to read. * @throws FileNotFoundException */ public LineReader(String file) throws FileNotFoundException { this(new FileReader(file)); } /** * Creates a new {@link LineReader}. * * @param stream The {@link Reader} containing the lines to read. */ public LineReader(Reader reader) { this.reader = new BufferedReader(reader); } /** * Creates an empty {@link LineReader} with no content. */ public LineReader() { this(new StringReader("")); } /** * Closes the underlying stream. */ @Override public void close() throws IOException { reader.close(); } /** * Makes sure the underlying stream is closed. */ @Override protected void finalize() throws Throwable { close(); } /** * Returns an iterator over the lines remaining to be read. * * <p>The underlying stream is closed automatically once {@link Iterator#hasNext()} * returns false, so closing it manually after using a for loop shouldn't be necessary. * * @return This iterator. */ @Override public Iterator<String> iterator() { return new LineIterator(); } /** * Returns all lines remaining to be read and closes the stream. * * @return The lines read from the stream. */ public Collection<String> readLines() { Collection<String> lines = new ArrayList<String>(); for(String line : this) { lines.add(line); } return lines; } private class LineIterator implements Iterator<String> { private String nextLine; public String bufferNext() { try { return nextLine = reader.readLine(); } catch (IOException e) { throw new IllegalStateException("I/O error while reading stream.", e); } } public boolean hasNext() { boolean hasNext = nextLine != null || bufferNext() != null; if ( ! hasNext) try { reader.close(); } catch (IOException e) { throw new IllegalStateException("I/O error when closing stream.", e); } return hasNext; } public String next() { if ( ! hasNext()) throw new NoSuchElementException(); String result = nextLine; nextLine = null; return result; } public void remove() { throw new UnsupportedOperationException(); } } } |
You can use it in a streaming fashion:
Or grab all the lines at once:
Collection<String> lines = new LineReader(stream).readLines();
Let me know what you think! Feedback is welcome as always 🙂