Reader是Java IO体系里字符处理读取流的基本类,代码如下
/* * %W% %E% * * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package java.io; /** * Abstract class for reading character streams. The only methods that a * subclass must implement are read(char[], int, int) and close(). Most * subclasses, however, will override some of the methods defined here in order * to provide higher efficiency, additional functionality, or both. * * * @see BufferedReader * @see LineNumberReader * @see CharArrayReader * @see InputStreamReader * @see FileReader * @see FilterReader * @see PushbackReader * @see PipedReader * @see StringReader * @see Writer * * @version %I%, %E% * @author Mark Reinhold * @since JDK1.1 */ public abstract class Reader implements Readable, Closeable { /** * 锁,在构造方法时赋值,默认使用this,也可以指定别的obj */ protected Object lock; /** * Creates a new character-stream reader whose critical sections will * synchronize on the reader itself. */ protected Reader() { this.lock = this; } /** * Creates a new character-stream reader whose critical sections will * synchronize on the given object. * * @param lock The Object to synchronize on. */ protected Reader(Object lock) { if (lock == null) { throw new NullPointerException(); } this.lock = lock; } /** * Attempts to read characters into the specified character buffer. * The buffer is used as a repository of characters as-is: the only * changes made are the results of a put operation. No flipping or * rewinding of the buffer is performed. * * @param target the buffer to read characters into * @return The number of characters added to the buffer, or * -1 if this source of characters is at its end * @throws IOException if an I/O error occurs * @throws NullPointerException if target is null * @throws ReadOnlyBufferException if target is a read only buffer * @since 1.5 */ public int read(java.nio.CharBuffer target) throws IOException { int len = target.remaining(); char[] cbuf = new char[len]; int n = read(cbuf, 0, len); if (n > 0) target.put(cbuf, 0, n); return n; } /** * 读取一个字符,实现方式是先读取一个字符到一个char数组中,最后返回数组的第一个元素 */ public int read() throws IOException { char cb[] = new char[1]; if (read(cb, 0, 1) == -1) return -1; else return cb[0]; } /** * 读取char[]数组长度的字符到数组中 */ public int read(char cbuf[]) throws IOException { return read(cbuf, 0, cbuf.length); } /** * 交给子类实现的读取方法 */ abstract public int read(char cbuf[], int off, int len) throws IOException; /** Maximum skip-buffer size */ private static final int maxSkipBufferSize = 8192; /** 用来支持skip方法的数组 */ private char skipBuffer[] = null; /** * 跳过指定数目的字符,实现方式是将指定字符读取出来并丢弃 * 另外,这个方法是个串行方法 */ public long skip(long n) throws IOException { if (n < 0L) throw new IllegalArgumentException("skip value is negative"); int nn = (int) Math.min(n, maxSkipBufferSize); synchronized (lock) { if ((skipBuffer == null) || (skipBuffer.length < nn)) skipBuffer = new char[nn]; long r = n; while (r > 0) { int nc = read(skipBuffer, 0, (int)Math.min(r, nn)); if (nc == -1) break; r -= nc; } return n - r; } } /** * 用来表示Reader中后面还有没有可读取的字符 * 在本类中始终返回false,在子类中有自己的实现 */ public boolean ready() throws IOException { return false; } /** * Tells whether this stream supports the mark() operation. The default * implementation always returns false. Subclasses should override this * method. * * @return true if and only if this stream supports the mark operation. */ public boolean markSupported() { return false; } /** * 在指定位置做一个标记,用处类似于ByteBuffer中的mark */ public void mark(int readAheadLimit) throws IOException { throw new IOException("mark() not supported"); } /** * 将position设置为mark */ public void reset() throws IOException { throw new IOException("reset() not supported"); } /** * Closes the stream and releases any system resources associated with * it. Once the stream has been closed, further read(), ready(), * mark(), reset(), or skip() invocations will throw an IOException. * Closing a previously closed stream has no effect. * * @exception IOException If an I/O error occurs */ abstract public void close() throws IOException; }
MultiReader
/* * Copyright (C) 2008 The Guava Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.common.io; import com.google.common.base.Preconditions; import java.io.IOException; import java.io.Reader; import java.util.Iterator; /** * 使用多个Reader合成一个MultiReader,其中Reader被Supplier包装起来 */ class MultiReader extends Reader { private final Iterator<? extends InputSupplier<? extends Reader>> it; /** 当前Reader */ private Reader current; MultiReader(Iterator<? extends InputSupplier<? extends Reader>> readers) throws IOException { this.it = readers; advance(); } /** * 关闭当前Reader并跳到下一个reader */ private void advance() throws IOException { close(); if (it.hasNext()) { current = it.next().getInput(); } } /** * 读取当前Reader的内容到cbuf[]中,如果当前reader已经读完,则切换到下一个reader来读取 */ @Override public int read(char cbuf[], int off, int len) throws IOException { if (current == null) { return -1; } int result = current.read(cbuf, off, len); if (result == -1) { advance(); return read(cbuf, off, len); } return result; } /** * 跳过指定个数目的字符,如果当前reader已经读完,则跳到下一个reader并重新读取 */ @Override public long skip(long n) throws IOException { Preconditions.checkArgument(n >= 0, "n is negative"); if (n > 0) { while (current != null) { long result = current.skip(n); if (result > 0) { return result; } advance(); } } return 0; } @Override public boolean ready() throws IOException { return (current != null) && current.ready(); } /** * 关闭当前reader */ @Override public void close() throws IOException { if (current != null) { try { current.close(); } finally { current = null; } } } }