View Javadoc
1   /*
2    * Copyright (C) 2007 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5    * in compliance with the License. You may obtain a copy of the License at
6    *
7    * http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software distributed under the License
10   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11   * or implied. See the License for the specific language governing permissions and limitations under
12   * the License.
13   */
14  
15  package com.google.common.io;
16  
17  import static com.google.common.base.Preconditions.checkNotNull;
18  import static com.google.common.io.CharStreams.createBuffer;
19  
20  import com.google.common.annotations.Beta;
21  import com.google.common.annotations.GwtIncompatible;
22  import com.google.errorprone.annotations.CanIgnoreReturnValue;
23  import java.io.IOException;
24  import java.io.Reader;
25  import java.nio.CharBuffer;
26  import java.util.LinkedList;
27  import java.util.Queue;
28  
29  /**
30   * A class for reading lines of text. Provides the same functionality as
31   * {@link java.io.BufferedReader#readLine()} but for all {@link Readable} objects, not just
32   * instances of {@link Reader}.
33   *
34   * @author Chris Nokleberg
35   * @since 1.0
36   */
37  @Beta
38  @GwtIncompatible
39  public final class LineReader {
40    private final Readable readable;
41    private final Reader reader;
42    private final CharBuffer cbuf = createBuffer();
43    private final char[] buf = cbuf.array();
44  
45    private final Queue<String> lines = new LinkedList<>();
46    private final LineBuffer lineBuf =
47        new LineBuffer() {
48          @Override
49          protected void handleLine(String line, String end) {
50            lines.add(line);
51          }
52        };
53  
54    /**
55     * Creates a new instance that will read lines from the given {@code Readable} object.
56     */
57    public LineReader(Readable readable) {
58      this.readable = checkNotNull(readable);
59      this.reader = (readable instanceof Reader) ? (Reader) readable : null;
60    }
61  
62    /**
63     * Reads a line of text. A line is considered to be terminated by any one of a line feed
64     * ({@code '\n'}), a carriage return ({@code '\r'}), or a carriage return followed immediately by
65     * a linefeed ({@code "\r\n"}).
66     *
67     * @return a {@code String} containing the contents of the line, not including any
68     *     line-termination characters, or {@code null} if the end of the stream has been reached.
69     * @throws IOException if an I/O error occurs
70     */
71    @CanIgnoreReturnValue // to skip a line
72    public String readLine() throws IOException {
73      while (lines.peek() == null) {
74        cbuf.clear();
75        // The default implementation of Reader#read(CharBuffer) allocates a
76        // temporary char[], so we call Reader#read(char[], int, int) instead.
77        int read = (reader != null)
78            ? reader.read(buf, 0, buf.length)
79            : readable.read(cbuf);
80        if (read == -1) {
81          lineBuf.finish();
82          break;
83        }
84        lineBuf.add(buf, 0, read);
85      }
86      return lines.poll();
87    }
88  }