1. /*
  2. * @(#)BufferedReader.java 1.20 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.io;
  8. /**
  9. * Read text from a character-input stream, buffering characters so as to
  10. * provide for the efficient reading of characters, arrays, and lines.
  11. *
  12. * <p> The buffer size may be specified, or the default size may be used. The
  13. * default is large enough for most purposes.
  14. *
  15. * <p> In general, each read request made of a Reader causes a corresponding
  16. * read request to be made of the underlying character or byte stream. It is
  17. * therefore advisable to wrap a BufferedReader around any Reader whose read()
  18. * operations may be costly, such as FileReaders and InputStreamReaders. For
  19. * example,
  20. *
  21. * <pre>
  22. * BufferedReader in
  23. * = new BufferedReader(new FileReader("foo.in"));
  24. * </pre>
  25. *
  26. * will buffer the input from the specified file. Without buffering, each
  27. * invocation of read() or readLine() could cause bytes to be read from the
  28. * file, converted into characters, and then returned, which can be very
  29. * inefficient.
  30. *
  31. * <p> Programs that use DataInputStreams for textual input can be localized by
  32. * replacing each DataInputStream with an appropriate BufferedReader.
  33. *
  34. * @see FileReader
  35. * @see InputStreamReader
  36. *
  37. * @version 1.20, 01/11/29
  38. * @author Mark Reinhold
  39. * @since JDK1.1
  40. */
  41. public class BufferedReader extends Reader {
  42. private Reader in;
  43. private char cb[];
  44. private int nChars, nextChar;
  45. private static final int INVALIDATED = -2;
  46. private static final int UNMARKED = -1;
  47. private int markedChar = UNMARKED;
  48. private int readAheadLimit = 0; /* Valid only when markedChar > 0 */
  49. private static int defaultCharBufferSize = 8192;
  50. private static int defaultExpectedLineLength = 80;
  51. /**
  52. * Create a buffering character-input stream that uses an input buffer of
  53. * the specified size.
  54. *
  55. * @param in A Reader
  56. * @param sz Input-buffer size
  57. *
  58. * @exception IllegalArgumentException If sz is <= 0
  59. */
  60. public BufferedReader(Reader in, int sz) {
  61. super(in);
  62. if (sz <= 0)
  63. throw new IllegalArgumentException("Buffer size <= 0");
  64. this.in = in;
  65. cb = new char[sz];
  66. nextChar = nChars = 0;
  67. }
  68. /**
  69. * Create a buffering character-input stream that uses a default-sized
  70. * input buffer.
  71. *
  72. * @param in A Reader
  73. */
  74. public BufferedReader(Reader in) {
  75. this(in, defaultCharBufferSize);
  76. }
  77. /** Check to make sure that the stream has not been closed */
  78. private void ensureOpen() throws IOException {
  79. if (in == null)
  80. throw new IOException("Stream closed");
  81. }
  82. /**
  83. * Fill the input buffer, taking the mark into account if it is valid.
  84. */
  85. private void fill() throws IOException {
  86. int dst;
  87. if (markedChar <= UNMARKED) {
  88. /* No mark */
  89. dst = 0;
  90. } else {
  91. /* Marked */
  92. int delta = nextChar - markedChar;
  93. if (delta >= readAheadLimit) {
  94. /* Gone past read-ahead limit: Invalidate mark */
  95. markedChar = INVALIDATED;
  96. readAheadLimit = 0;
  97. dst = 0;
  98. } else {
  99. if (readAheadLimit <= cb.length) {
  100. /* Shuffle in the current buffer */
  101. System.arraycopy(cb, markedChar, cb, 0, delta);
  102. markedChar = 0;
  103. dst = delta;
  104. } else {
  105. /* Reallocate buffer to accomodate read-ahead limit */
  106. char ncb[] = new char[readAheadLimit];
  107. System.arraycopy(cb, markedChar, ncb, 0, delta);
  108. cb = ncb;
  109. markedChar = 0;
  110. dst = delta;
  111. }
  112. nextChar = nChars = delta;
  113. }
  114. }
  115. int n;
  116. do {
  117. n = in.read(cb, dst, cb.length - dst);
  118. } while (n == 0);
  119. if (n > 0) {
  120. nChars = dst + n;
  121. nextChar = dst;
  122. }
  123. }
  124. /**
  125. * Read a single character.
  126. *
  127. * @exception IOException If an I/O error occurs
  128. */
  129. public int read() throws IOException {
  130. synchronized (lock) {
  131. ensureOpen();
  132. if (nextChar >= nChars) {
  133. fill();
  134. if (nextChar >= nChars)
  135. return -1;
  136. }
  137. return cb[nextChar++];
  138. }
  139. }
  140. /**
  141. * Read characters into a portion of an array, reading from the underlying
  142. * stream at most once if necessary.
  143. */
  144. private int read1(char[] cbuf, int off, int len) throws IOException {
  145. if (nextChar >= nChars) {
  146. /* If the requested length is at least as large as the buffer, and
  147. if there is no mark/reset activity, do not bother to copy the
  148. characters into the local buffer. In this way buffered streams
  149. will cascade harmlessly. */
  150. if (len >= cb.length && markedChar <= UNMARKED) {
  151. return in.read(cbuf, off, len);
  152. }
  153. fill();
  154. }
  155. if (nextChar >= nChars) return -1;
  156. int n = Math.min(len, nChars - nextChar);
  157. System.arraycopy(cb, nextChar, cbuf, off, n);
  158. nextChar += n;
  159. return n;
  160. }
  161. /**
  162. * Read characters into a portion of an array.
  163. *
  164. * <p> This method implements the general contract of the corresponding
  165. * <code>{@link Reader#read(char[], int, int) read}</code> method of the
  166. * <code>{@link Reader}</code> class. As an additional convenience, it
  167. * attempts to read as many characters as possible by repeatedly invoking
  168. * the <code>read</code> method of the underlying stream. This iterated
  169. * <code>read</code> continues until one of the following conditions becomes
  170. * true: <ul>
  171. *
  172. * <li> The specified number of characters have been read,
  173. *
  174. * <li> The <code>read</code> method of the underlying stream returns
  175. * <code>-1</code>, indicating end-of-file, or
  176. *
  177. * <li> The <code>ready</code> method of the underlying stream
  178. * returns <code>false</code>, indicating that further input requests
  179. * would block.
  180. *
  181. * </ul> If the first <code>read</code> on the underlying stream returns
  182. * <code>-1</code> to indicate end-of-file then this method returns
  183. * <code>-1</code>. Otherwise this method returns the number of characters
  184. * actually read.
  185. *
  186. * <p> Subclasses of this class are encouraged, but not required, to
  187. * attempt to read as many characters as possible in the same fashion.
  188. *
  189. * <p> Ordinarily this method takes characters from this stream's character
  190. * buffer, filling it from the underlying stream as necessary. If,
  191. * however, the buffer is empty, the mark is not valid, and the requested
  192. * length is at least as large as the buffer, then this method will read
  193. * characters directly from the underlying stream into the given array.
  194. * Thus redundant <code>BufferedReader</code>s will not copy data
  195. * unnecessarily.
  196. *
  197. * @param cbuf Destination buffer
  198. * @param off Offset at which to start storing characters
  199. * @param len Maximum number of characters to read
  200. *
  201. * @return The number of characters read, or -1 if the end of the
  202. * stream has been reached
  203. *
  204. * @exception IOException If an I/O error occurs
  205. */
  206. public int read(char cbuf[], int off, int len) throws IOException {
  207. synchronized (lock) {
  208. ensureOpen();
  209. if ((off < 0) || (off > cbuf.length) || (len < 0) ||
  210. ((off + len) > cbuf.length) || ((off + len) < 0)) {
  211. throw new IndexOutOfBoundsException();
  212. } else if (len == 0) {
  213. return 0;
  214. }
  215. int n = read1(cbuf, off, len);
  216. if (n <= 0) return n;
  217. while ((n < len) && in.ready()) {
  218. int n1 = read1(cbuf, off + n, len - n);
  219. if (n1 <= 0) break;
  220. n += n1;
  221. }
  222. return n;
  223. }
  224. }
  225. /**
  226. * Read a line of text. A line is considered to be terminated by any one
  227. * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
  228. * followed immediately by a linefeed.
  229. *
  230. * @param skipLF If true, the next '\n' will be skipped
  231. *
  232. * @return A String containing the contents of the line, not including
  233. * any line-termination characters, or null if the end of the
  234. * stream has been reached
  235. *
  236. * @see java.io.LineNumberReader#readLine()
  237. *
  238. * @exception IOException If an I/O error occurs
  239. */
  240. String readLine(boolean skipLF) throws IOException {
  241. StringBuffer s = new StringBuffer(defaultExpectedLineLength);
  242. synchronized (lock) {
  243. ensureOpen();
  244. bufferLoop:
  245. for (;;) {
  246. if (nextChar >= nChars)
  247. fill();
  248. if (nextChar >= nChars) { /* EOF */
  249. if (s.length() > 0)
  250. return s.toString();
  251. else
  252. return null;
  253. }
  254. boolean eol = false;
  255. char c = 0;
  256. int i;
  257. /* Skip a leftover '\n' */
  258. if (skipLF && (cb[nextChar] == '\n'))
  259. nextChar++;
  260. charLoop:
  261. for (i = nextChar; i < nChars; i++) {
  262. c = cb[i];
  263. if ((c == '\n') || (c == '\r')) {
  264. eol = true;
  265. break charLoop;
  266. }
  267. }
  268. s.append(cb, nextChar, i - nextChar);
  269. nextChar = i;
  270. if (eol) {
  271. nextChar++;
  272. if (c == '\r') {
  273. if (nextChar >= nChars)
  274. fill();
  275. if ((nextChar < nChars) && (cb[nextChar] == '\n'))
  276. nextChar++;
  277. }
  278. break bufferLoop;
  279. }
  280. skipLF = false;
  281. }
  282. }
  283. return s.toString();
  284. }
  285. /**
  286. * Read a line of text. A line is considered to be terminated by any one
  287. * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
  288. * followed immediately by a linefeed.
  289. *
  290. * @return A String containing the contents of the line, not including
  291. * any line-termination characters, or null if the end of the
  292. * stream has been reached
  293. *
  294. * @exception IOException If an I/O error occurs
  295. */
  296. public String readLine() throws IOException {
  297. return readLine(false);
  298. }
  299. /**
  300. * Skip characters.
  301. *
  302. * @param n The number of characters to skip
  303. *
  304. * @return The number of characters actually skipped
  305. *
  306. * @exception IOException If an I/O error occurs
  307. */
  308. public long skip(long n) throws IOException {
  309. if (n < 0L) {
  310. throw new IllegalArgumentException("skip value is negative");
  311. }
  312. synchronized (lock) {
  313. ensureOpen();
  314. long r = n;
  315. while (r > 0) {
  316. if (nextChar >= nChars)
  317. fill();
  318. if (nextChar >= nChars) /* EOF */
  319. break;
  320. long d = nChars - nextChar;
  321. if (r <= d) {
  322. nextChar += r;
  323. r = 0;
  324. break;
  325. }
  326. else {
  327. r -= d;
  328. nextChar = nChars;
  329. }
  330. }
  331. return n - r;
  332. }
  333. }
  334. /**
  335. * Tell whether this stream is ready to be read. A buffered character
  336. * stream is ready if the buffer is not empty, or if the underlying
  337. * character stream is ready.
  338. *
  339. * @exception IOException If an I/O error occurs
  340. */
  341. public boolean ready() throws IOException {
  342. synchronized (lock) {
  343. ensureOpen();
  344. return (nextChar < nChars) || in.ready();
  345. }
  346. }
  347. /**
  348. * Tell whether this stream supports the mark() operation, which it does.
  349. */
  350. public boolean markSupported() {
  351. return true;
  352. }
  353. /**
  354. * Mark the present position in the stream. Subsequent calls to reset()
  355. * will attempt to reposition the stream to this point.
  356. *
  357. * @param readAheadLimit Limit on the number of characters that may be
  358. * read while still preserving the mark. After
  359. * reading this many characters, attempting to
  360. * reset the stream may fail. A limit value larger
  361. * than the size of the input buffer will cause a
  362. * new buffer to be allocated whose size is no
  363. * smaller than limit. Therefore large values
  364. * should be used with care.
  365. *
  366. * @exception IllegalArgumentException If readAheadLimit is < 0
  367. * @exception IOException If an I/O error occurs
  368. */
  369. public void mark(int readAheadLimit) throws IOException {
  370. if (readAheadLimit < 0) {
  371. throw new IllegalArgumentException("Read-ahead limit < 0");
  372. }
  373. synchronized (lock) {
  374. ensureOpen();
  375. this.readAheadLimit = readAheadLimit;
  376. markedChar = nextChar;
  377. }
  378. }
  379. /**
  380. * Reset the stream to the most recent mark.
  381. *
  382. * @exception IOException If the stream has never been marked,
  383. * or if the mark has been invalidated
  384. */
  385. public void reset() throws IOException {
  386. synchronized (lock) {
  387. ensureOpen();
  388. if (markedChar < 0)
  389. throw new IOException((markedChar == INVALIDATED)
  390. ? "Mark invalid"
  391. : "Stream not marked");
  392. nextChar = markedChar;
  393. }
  394. }
  395. /**
  396. * Close the stream.
  397. *
  398. * @exception IOException If an I/O error occurs
  399. */
  400. public void close() throws IOException {
  401. synchronized (lock) {
  402. if (in == null)
  403. return;
  404. in.close();
  405. in = null;
  406. cb = null;
  407. }
  408. }
  409. }