Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/io/BufferedReader.java
38829 views
/*1* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.io;262728import java.util.Iterator;29import java.util.NoSuchElementException;30import java.util.Spliterator;31import java.util.Spliterators;32import java.util.stream.Stream;33import java.util.stream.StreamSupport;3435/**36* Reads text from a character-input stream, buffering characters so as to37* provide for the efficient reading of characters, arrays, and lines.38*39* <p> The buffer size may be specified, or the default size may be used. The40* default is large enough for most purposes.41*42* <p> In general, each read request made of a Reader causes a corresponding43* read request to be made of the underlying character or byte stream. It is44* therefore advisable to wrap a BufferedReader around any Reader whose read()45* operations may be costly, such as FileReaders and InputStreamReaders. For46* example,47*48* <pre>49* BufferedReader in50* = new BufferedReader(new FileReader("foo.in"));51* </pre>52*53* will buffer the input from the specified file. Without buffering, each54* invocation of read() or readLine() could cause bytes to be read from the55* file, converted into characters, and then returned, which can be very56* inefficient.57*58* <p> Programs that use DataInputStreams for textual input can be localized by59* replacing each DataInputStream with an appropriate BufferedReader.60*61* @see FileReader62* @see InputStreamReader63* @see java.nio.file.Files#newBufferedReader64*65* @author Mark Reinhold66* @since JDK1.167*/6869public class BufferedReader extends Reader {7071private Reader in;7273private char cb[];74private int nChars, nextChar;7576private static final int INVALIDATED = -2;77private static final int UNMARKED = -1;78private int markedChar = UNMARKED;79private int readAheadLimit = 0; /* Valid only when markedChar > 0 */8081/** If the next character is a line feed, skip it */82private boolean skipLF = false;8384/** The skipLF flag when the mark was set */85private boolean markedSkipLF = false;8687private static int defaultCharBufferSize = 8192;88private static int defaultExpectedLineLength = 80;8990/**91* Creates a buffering character-input stream that uses an input buffer of92* the specified size.93*94* @param in A Reader95* @param sz Input-buffer size96*97* @exception IllegalArgumentException If {@code sz <= 0}98*/99public BufferedReader(Reader in, int sz) {100super(in);101if (sz <= 0)102throw new IllegalArgumentException("Buffer size <= 0");103this.in = in;104cb = new char[sz];105nextChar = nChars = 0;106}107108/**109* Creates a buffering character-input stream that uses a default-sized110* input buffer.111*112* @param in A Reader113*/114public BufferedReader(Reader in) {115this(in, defaultCharBufferSize);116}117118/** Checks to make sure that the stream has not been closed */119private void ensureOpen() throws IOException {120if (in == null)121throw new IOException("Stream closed");122}123124/**125* Fills the input buffer, taking the mark into account if it is valid.126*/127private void fill() throws IOException {128int dst;129if (markedChar <= UNMARKED) {130/* No mark */131dst = 0;132} else {133/* Marked */134int delta = nextChar - markedChar;135if (delta >= readAheadLimit) {136/* Gone past read-ahead limit: Invalidate mark */137markedChar = INVALIDATED;138readAheadLimit = 0;139dst = 0;140} else {141if (readAheadLimit <= cb.length) {142/* Shuffle in the current buffer */143System.arraycopy(cb, markedChar, cb, 0, delta);144markedChar = 0;145dst = delta;146} else {147/* Reallocate buffer to accommodate read-ahead limit */148char ncb[] = new char[readAheadLimit];149System.arraycopy(cb, markedChar, ncb, 0, delta);150cb = ncb;151markedChar = 0;152dst = delta;153}154nextChar = nChars = delta;155}156}157158int n;159do {160n = in.read(cb, dst, cb.length - dst);161} while (n == 0);162if (n > 0) {163nChars = dst + n;164nextChar = dst;165}166}167168/**169* Reads a single character.170*171* @return The character read, as an integer in the range172* 0 to 65535 (<tt>0x00-0xffff</tt>), or -1 if the173* end of the stream has been reached174* @exception IOException If an I/O error occurs175*/176public int read() throws IOException {177synchronized (lock) {178ensureOpen();179for (;;) {180if (nextChar >= nChars) {181fill();182if (nextChar >= nChars)183return -1;184}185if (skipLF) {186skipLF = false;187if (cb[nextChar] == '\n') {188nextChar++;189continue;190}191}192return cb[nextChar++];193}194}195}196197/**198* Reads characters into a portion of an array, reading from the underlying199* stream if necessary.200*/201private int read1(char[] cbuf, int off, int len) throws IOException {202if (nextChar >= nChars) {203/* If the requested length is at least as large as the buffer, and204if there is no mark/reset activity, and if line feeds are not205being skipped, do not bother to copy the characters into the206local buffer. In this way buffered streams will cascade207harmlessly. */208if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {209return in.read(cbuf, off, len);210}211fill();212}213if (nextChar >= nChars) return -1;214if (skipLF) {215skipLF = false;216if (cb[nextChar] == '\n') {217nextChar++;218if (nextChar >= nChars)219fill();220if (nextChar >= nChars)221return -1;222}223}224int n = Math.min(len, nChars - nextChar);225System.arraycopy(cb, nextChar, cbuf, off, n);226nextChar += n;227return n;228}229230/**231* Reads characters into a portion of an array.232*233* <p> This method implements the general contract of the corresponding234* <code>{@link Reader#read(char[], int, int) read}</code> method of the235* <code>{@link Reader}</code> class. As an additional convenience, it236* attempts to read as many characters as possible by repeatedly invoking237* the <code>read</code> method of the underlying stream. This iterated238* <code>read</code> continues until one of the following conditions becomes239* true: <ul>240*241* <li> The specified number of characters have been read,242*243* <li> The <code>read</code> method of the underlying stream returns244* <code>-1</code>, indicating end-of-file, or245*246* <li> The <code>ready</code> method of the underlying stream247* returns <code>false</code>, indicating that further input requests248* would block.249*250* </ul> If the first <code>read</code> on the underlying stream returns251* <code>-1</code> to indicate end-of-file then this method returns252* <code>-1</code>. Otherwise this method returns the number of characters253* actually read.254*255* <p> Subclasses of this class are encouraged, but not required, to256* attempt to read as many characters as possible in the same fashion.257*258* <p> Ordinarily this method takes characters from this stream's character259* buffer, filling it from the underlying stream as necessary. If,260* however, the buffer is empty, the mark is not valid, and the requested261* length is at least as large as the buffer, then this method will read262* characters directly from the underlying stream into the given array.263* Thus redundant <code>BufferedReader</code>s will not copy data264* unnecessarily.265*266* @param cbuf Destination buffer267* @param off Offset at which to start storing characters268* @param len Maximum number of characters to read269*270* @return The number of characters read, or -1 if the end of the271* stream has been reached272*273* @exception IOException If an I/O error occurs274*/275public int read(char cbuf[], int off, int len) throws IOException {276synchronized (lock) {277ensureOpen();278if ((off < 0) || (off > cbuf.length) || (len < 0) ||279((off + len) > cbuf.length) || ((off + len) < 0)) {280throw new IndexOutOfBoundsException();281} else if (len == 0) {282return 0;283}284285int n = read1(cbuf, off, len);286if (n <= 0) return n;287while ((n < len) && in.ready()) {288int n1 = read1(cbuf, off + n, len - n);289if (n1 <= 0) break;290n += n1;291}292return n;293}294}295296/**297* Reads a line of text. A line is considered to be terminated by any one298* of a line feed ('\n'), a carriage return ('\r'), or a carriage return299* followed immediately by a linefeed.300*301* @param ignoreLF If true, the next '\n' will be skipped302*303* @return A String containing the contents of the line, not including304* any line-termination characters, or null if the end of the305* stream has been reached306*307* @see java.io.LineNumberReader#readLine()308*309* @exception IOException If an I/O error occurs310*/311String readLine(boolean ignoreLF) throws IOException {312StringBuilder s = null;313int startChar;314315synchronized (lock) {316ensureOpen();317boolean omitLF = ignoreLF || skipLF;318319bufferLoop:320for (;;) {321322if (nextChar >= nChars)323fill();324if (nextChar >= nChars) { /* EOF */325if (s != null && s.length() > 0)326return s.toString();327else328return null;329}330boolean eol = false;331char c = 0;332int i;333334/* Skip a leftover '\n', if necessary */335if (omitLF && (cb[nextChar] == '\n'))336nextChar++;337skipLF = false;338omitLF = false;339340charLoop:341for (i = nextChar; i < nChars; i++) {342c = cb[i];343if ((c == '\n') || (c == '\r')) {344eol = true;345break charLoop;346}347}348349startChar = nextChar;350nextChar = i;351352if (eol) {353String str;354if (s == null) {355str = new String(cb, startChar, i - startChar);356} else {357s.append(cb, startChar, i - startChar);358str = s.toString();359}360nextChar++;361if (c == '\r') {362skipLF = true;363}364return str;365}366367if (s == null)368s = new StringBuilder(defaultExpectedLineLength);369s.append(cb, startChar, i - startChar);370}371}372}373374/**375* Reads a line of text. A line is considered to be terminated by any one376* of a line feed ('\n'), a carriage return ('\r'), or a carriage return377* followed immediately by a linefeed.378*379* @return A String containing the contents of the line, not including380* any line-termination characters, or null if the end of the381* stream has been reached382*383* @exception IOException If an I/O error occurs384*385* @see java.nio.file.Files#readAllLines386*/387public String readLine() throws IOException {388return readLine(false);389}390391/**392* Skips characters.393*394* @param n The number of characters to skip395*396* @return The number of characters actually skipped397*398* @exception IllegalArgumentException If <code>n</code> is negative.399* @exception IOException If an I/O error occurs400*/401public long skip(long n) throws IOException {402if (n < 0L) {403throw new IllegalArgumentException("skip value is negative");404}405synchronized (lock) {406ensureOpen();407long r = n;408while (r > 0) {409if (nextChar >= nChars)410fill();411if (nextChar >= nChars) /* EOF */412break;413if (skipLF) {414skipLF = false;415if (cb[nextChar] == '\n') {416nextChar++;417}418}419long d = nChars - nextChar;420if (r <= d) {421nextChar += r;422r = 0;423break;424}425else {426r -= d;427nextChar = nChars;428}429}430return n - r;431}432}433434/**435* Tells whether this stream is ready to be read. A buffered character436* stream is ready if the buffer is not empty, or if the underlying437* character stream is ready.438*439* @exception IOException If an I/O error occurs440*/441public boolean ready() throws IOException {442synchronized (lock) {443ensureOpen();444445/*446* If newline needs to be skipped and the next char to be read447* is a newline character, then just skip it right away.448*/449if (skipLF) {450/* Note that in.ready() will return true if and only if the next451* read on the stream will not block.452*/453if (nextChar >= nChars && in.ready()) {454fill();455}456if (nextChar < nChars) {457if (cb[nextChar] == '\n')458nextChar++;459skipLF = false;460}461}462return (nextChar < nChars) || in.ready();463}464}465466/**467* Tells whether this stream supports the mark() operation, which it does.468*/469public boolean markSupported() {470return true;471}472473/**474* Marks the present position in the stream. Subsequent calls to reset()475* will attempt to reposition the stream to this point.476*477* @param readAheadLimit Limit on the number of characters that may be478* read while still preserving the mark. An attempt479* to reset the stream after reading characters480* up to this limit or beyond may fail.481* A limit value larger than the size of the input482* buffer will cause a new buffer to be allocated483* whose size is no smaller than limit.484* Therefore large values should be used with care.485*486* @exception IllegalArgumentException If {@code readAheadLimit < 0}487* @exception IOException If an I/O error occurs488*/489public void mark(int readAheadLimit) throws IOException {490if (readAheadLimit < 0) {491throw new IllegalArgumentException("Read-ahead limit < 0");492}493synchronized (lock) {494ensureOpen();495this.readAheadLimit = readAheadLimit;496markedChar = nextChar;497markedSkipLF = skipLF;498}499}500501/**502* Resets the stream to the most recent mark.503*504* @exception IOException If the stream has never been marked,505* or if the mark has been invalidated506*/507public void reset() throws IOException {508synchronized (lock) {509ensureOpen();510if (markedChar < 0)511throw new IOException((markedChar == INVALIDATED)512? "Mark invalid"513: "Stream not marked");514nextChar = markedChar;515skipLF = markedSkipLF;516}517}518519public void close() throws IOException {520synchronized (lock) {521if (in == null)522return;523try {524in.close();525} finally {526in = null;527cb = null;528}529}530}531532/**533* Returns a {@code Stream}, the elements of which are lines read from534* this {@code BufferedReader}. The {@link Stream} is lazily populated,535* i.e., read only occurs during the536* <a href="../util/stream/package-summary.html#StreamOps">terminal537* stream operation</a>.538*539* <p> The reader must not be operated on during the execution of the540* terminal stream operation. Otherwise, the result of the terminal stream541* operation is undefined.542*543* <p> After execution of the terminal stream operation there are no544* guarantees that the reader will be at a specific position from which to545* read the next character or line.546*547* <p> If an {@link IOException} is thrown when accessing the underlying548* {@code BufferedReader}, it is wrapped in an {@link549* UncheckedIOException} which will be thrown from the {@code Stream}550* method that caused the read to take place. This method will return a551* Stream if invoked on a BufferedReader that is closed. Any operation on552* that stream that requires reading from the BufferedReader after it is553* closed, will cause an UncheckedIOException to be thrown.554*555* @return a {@code Stream<String>} providing the lines of text556* described by this {@code BufferedReader}557*558* @since 1.8559*/560public Stream<String> lines() {561Iterator<String> iter = new Iterator<String>() {562String nextLine = null;563564@Override565public boolean hasNext() {566if (nextLine != null) {567return true;568} else {569try {570nextLine = readLine();571return (nextLine != null);572} catch (IOException e) {573throw new UncheckedIOException(e);574}575}576}577578@Override579public String next() {580if (nextLine != null || hasNext()) {581String line = nextLine;582nextLine = null;583return line;584} else {585throw new NoSuchElementException();586}587}588};589return StreamSupport.stream(Spliterators.spliteratorUnknownSize(590iter, Spliterator.ORDERED | Spliterator.NONNULL), false);591}592}593594595