📄 bufferedreader.java
字号:
* * @exception IOException If an error occurs. */ public int read(char[] buf, int offset, int count) throws IOException { synchronized (lock) { checkStatus(); // Once again, we need to handle the special case of a readLine // that has a '\r' at the end of the buffer. In this case, we'll // need to skip a '\n' if it is the next char to be read. // This special case is indicated by 'pos > limit'. boolean retAtEndOfBuffer = false; int avail = limit - pos; if (count > avail) { if (avail > 0) count = avail; else // pos >= limit { if (limit == buffer.length) markPos = -1; // read too far - invalidate the mark. if (pos > limit) { // Set a boolean and make pos == limit to simplify things. retAtEndOfBuffer = true; --pos; } if (markPos < 0) { // Optimization: can read directly into buf. if (count >= buffer.length && !retAtEndOfBuffer) return in.read(buf, offset, count); pos = limit = 0; } avail = in.read(buffer, limit, buffer.length - limit); if (retAtEndOfBuffer && avail > 0 && buffer[limit] == '\n') { --avail; limit++; } if (avail < count) { if (avail <= 0) return avail; count = avail; } limit += avail; } } System.arraycopy(buffer, pos, buf, offset, count); pos += count; return count; } } /* Read more data into the buffer. Update pos and limit appropriately. Assumes pos==limit initially. May invalidate the mark if read too much. Return number of chars read (never 0), or -1 on eof. */ private int fill() throws IOException { checkStatus(); // Handle the special case of a readLine that has a '\r' at the end of // the buffer. In this case, we'll need to skip a '\n' if it is the // next char to be read. This special case is indicated by 'pos > limit'. boolean retAtEndOfBuffer = false; if (pos > limit) { retAtEndOfBuffer = true; --pos; } if (markPos >= 0 && limit == buffer.length) markPos = -1; if (markPos < 0) pos = limit = 0; int count = in.read(buffer, limit, buffer.length - limit); if (count > 0) limit += count; if (retAtEndOfBuffer && buffer[pos] == '\n') { --count; // If the mark was set to the location of the \n, then we // must change it to fully pretend that the \n does not // exist. if (markPos == pos) ++markPos; ++pos; } return count; } public int read() throws IOException { synchronized (lock) { checkStatus(); if (pos >= limit && fill () <= 0) return -1; return buffer[pos++]; } } /* Return the end of the line starting at this.pos and ending at limit. * The index returns is *before* any line terminators, or limit * if no line terminators were found. */ private int lineEnd(int limit) { int i = pos; for (; i < limit; i++) { char ch = buffer[i]; if (ch == '\n' || ch == '\r') break; } return i; } /** * This method reads a single line of text from the input stream, returning * it as a <code>String</code>. A line is terminated by "\n", a "\r", or * an "\r\n" sequence. The system dependent line separator is not used. * The line termination characters are not returned in the resulting * <code>String</code>. * * @return The line of text read, or <code>null</code> if end of stream. * * @exception IOException If an error occurs */ public String readLine() throws IOException { checkStatus(); // Handle the special case where a previous readLine (with no intervening // reads/skips) had a '\r' at the end of the buffer. // In this case, we'll need to skip a '\n' if it's the next char to be read. // This special case is indicated by 'pos > limit'. if (pos > limit) { int ch = read(); if (ch < 0) return null; if (ch != '\n') --pos; } int i = lineEnd(limit); if (i < limit) { String str = new String(buffer, pos, i - pos); pos = i + 1; // If the last char in the buffer is a '\r', we must remember // to check if the next char to be read after the buffer is refilled // is a '\n'. If so, skip it. To indicate this condition, we set pos // to be limit + 1, which normally is never possible. if (buffer[i] == '\r') if (pos == limit || buffer[pos] == '\n') pos++; return str; } StringBuffer sbuf = new StringBuffer(200); sbuf.append(buffer, pos, i - pos); pos = i; // We only want to return null when no characters were read before // EOF. So we must keep track of this separately. Otherwise we // would treat an empty `sbuf' as an EOF condition, which is wrong // when there is just a newline. boolean eof = false; for (;;) { int ch = read(); if (ch < 0) { eof = true; break; } if (ch == '\n' || ch == '\r') { // Check here if a '\r' was the last char in the buffer; if so, // mark it as in the comment above to indicate future reads // should skip a newline that is the next char read after // refilling the buffer. if (ch == '\r') if (pos == limit || buffer[pos] == '\n') pos++; break; } i = lineEnd(limit); sbuf.append(buffer, pos - 1, i - (pos - 1)); pos = i; } return (sbuf.length() == 0 && eof) ? null : sbuf.toString(); } /** * This method skips the specified number of chars in the stream. It * returns the actual number of chars skipped, which may be less than the * requested amount. * <p> * This method first discards chars in the buffer, then calls the * <code>skip</code> method on the underlying stream to skip the remaining chars. * * @param num_chars The requested number of chars to skip * * @return The actual number of chars skipped. * * @exception IOException If an error occurs */ public long skip(long count) throws IOException { synchronized (lock) { checkStatus(); if (count <= 0) return 0; // Yet again, we need to handle the special case of a readLine // that has a '\r' at the end of the buffer. In this case, we need // to ignore a '\n' if it is the next char to be read. // This special case is indicated by 'pos > limit' (i.e. avail < 0). // To simplify things, if we're dealing with the special case for // readLine, just read the next char (since the fill method will // skip the '\n' for us). By doing this, we'll have to back up pos. // That's easier than trying to keep track of whether we've skipped // one element or not. int ch; if (pos > limit) if ((ch = read()) < 0) return 0; else --pos; int avail = limit - pos; if (count < avail) { pos += count; return count; } pos = limit; long todo = count - avail; if (todo > buffer.length) { markPos = -1; todo -= in.skip(todo); } else { while (todo > 0) { avail = fill(); if (avail <= 0) break; if (avail > todo) avail = (int) todo; pos += avail; todo -= avail; } } return count - todo; } } private void checkStatus() throws IOException { if (in == null) throw new IOException("Stream closed"); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -