java-io-源码-字符流-Reader
一. Reader
继承关系:FileReader->InputStreamReader->Reader->Readable
Readable
最上层的Readable接口只有一个方法read,该方法会把内容读取到传入的CharBuffer中
public interface Readable {
    public int read(java.nio.CharBuffer cb) throws IOException;
}
Reader
Reader内部有lock
覆盖了Readerable的read方法如下
    public int read(java.nio.CharBuffer target) throws IOException {
        int len = target.remaining();
        char[] cbuf = new char[len];
		//这个read是抽象方法
        int n = read(cbuf, 0, len);
        if (n > 0)
            target.put(cbuf, 0, n);
        return n;
    }
按照CharBuffer剩余的空间,读取内容,把CharBuffer填充满,把内容写入其中;
read(cbuf, 0, len)是抽象的方法,在子类中实现;
其他方法,调用的read都是子类实现的read(cbuf, 0, len)方法
read()				//一次读一个字符
read(char cbuf[])	//一次读满char数组
skip(long n) 		//skip方法
ready()				//是否可读了
markSupported()		//是否支持mark
mark(int readAheadLimit) 	//mark功能
reset()						//reset功能
close()						//关闭
InputStreamReader
InputStreamReader内部维持一个StreamDecode
private final StreamDecoder sd;
构造函数有三个
public InputStreamReader(InputStream in)
public InputStreamReader(InputStream in, String charsetName)
public InputStreamReader(InputStream in, Charset cs)
不指定Charset的StreamDecoder是默认的,构造时传入的InputStream作为父类的lock
InputStreamReader调用的方法都是StreamDecode的方法
包括:
getEncoding
read()
read(char cbuf[], int offset, int length)	//重写父类的抽象方法
ready()
close()
二. StreamDecoder
构造方法forInputStreamReader,由InputStreamReader调用生成,默认utf8
    public static StreamDecoder forInputStreamReader(InputStream in,
                                                     Object lock,
                                                     String charsetName)
        throws UnsupportedEncodingException
    {
        String csn = charsetName;
        if (csn == null)
            csn = Charset.defaultCharset().name();
        try {
            if (Charset.isSupported(csn))
                return new StreamDecoder(in, lock, Charset.forName(csn));
        } catch (IllegalCharsetNameException x) { }
        throw new UnsupportedEncodingException (csn);
    }
Charset.forName(csn)生成字符集
    public static Charset forName(String charsetName) {
        Charset cs = lookup(charsetName);
        if (cs != null)
            return cs;
        throw new UnsupportedCharsetException(charsetName);
    }
先调用lookup寻找这字符集
    private static Charset lookup(String charsetName) {
        if (charsetName == null)
            throw new IllegalArgumentException("Null charset name");
        Object[] a;
		//故意让缓存失效
        if ((a = cache1) != null && charsetName.equals(a[0]))
            return (Charset)a[1];
        return lookup2(charsetName);
    }
调用lookup2寻找
    private static Charset lookup2(String charsetName) {
        Object[] a;
        if ((a = cache2) != null && charsetName.equals(a[0])) {
            cache2 = cache1;
            cache1 = a;
            return (Charset)a[1];
        }
        Charset cs;
        if ((cs = standardProvider.charsetForName(charsetName)) != null ||
            (cs = lookupExtendedCharset(charsetName))           != null ||
            (cs = lookupViaProviders(charsetName))              != null)
        {
            cache(charsetName, cs);
            return cs;
        }
        checkName(charsetName);
        return null;
    }
分别利用standardProvider、lookupExtendedCharset、lookupViaProviders三个方法查找,如果都查找不多就检查输入名称
把standardProvider作为例子,经过很多个过程,最后利用反射产生对象
   private Charset lookup(String charsetName) {
        String csn = canonicalize(toLower(charsetName));
        Charset cs = cache.get(csn);
        if (cs != null)
            return cs;
        // Do we even support this charset?
        String cln = classMap.get(csn);
        if (cln == null)
            return null;
        if (cln.equals("US_ASCII")) {
            cs = new US_ASCII();
            cache.put(csn, cs);
            return cs;
        }
        // Instantiate the charset and cache it
        try {
            Class<?> c = Class.forName(packagePrefix + "." + cln,
                                    true,
                                    this.getClass().getClassLoader());
            cs = (Charset)c.newInstance();
            cache.put(csn, cs);
            return cs;
        } catch (ClassNotFoundException |
                 IllegalAccessException |
                 InstantiationException x) {
            return null;
        }
    }
查找字符集,其中前缀是sun.nio.cs,别名utf-8,构造并返回utf8字符集
  StreamDecoder(InputStream in, Object lock, Charset cs) {
        this(in, lock,
         cs.newDecoder()
         .onMalformedInput(CodingErrorAction.REPLACE)
         .onUnmappableCharacter(CodingErrorAction.REPLACE));
    }
最后在回到StreamDecoder的构造方法,初始化了内部维持的charset,decoder
如果是FileInputStream,那么打开一个channel
    StreamDecoder(InputStream in, Object lock, CharsetDecoder dec) {
        super(lock);
        this.cs = dec.charset();
        this.decoder = dec;
        if (false && in instanceof FileInputStream) {
		//利用这个FileInputStream构造一个channel
        ch = getChannel((FileInputStream)in);
        if (ch != null)
            bb = ByteBuffer.allocateDirect(DEFAULT_BYTE_BUFFER_SIZE);
        }
        if (ch == null) {
        this.in = in;
        this.ch = null;
        bb = ByteBuffer.allocate(DEFAULT_BYTE_BUFFER_SIZE);
        }
        bb.flip();                      // So that bb is initially empty
    }
然后分配一个ByteBuffer,这ByteBuffer调用flip
getChannel
如果传入的是FileInputStream,创建它的channel
  public FileChannel getChannel() {
        synchronized (this) {
            if (channel == null) {
                channel = FileChannelImpl.open(fd, path, true, false, this);
            }
            return channel;
        }
    }
创建一个FileChannelImpl
  private FileChannelImpl(FileDescriptor fd, boolean readable,
                            boolean writable, boolean append, Object parent)
    {
        this.fd = fd;
        this.readable = readable;
        this.writable = writable;
        this.append = append;
        this.parent = parent;
        this.nd = new FileDispatcherImpl(append);
    }
内部持有一个FileDispatcherImpl
三. 读操作
继续分析InputStreamReader的读操作
如果指定字符集,那么会更新内部的解码器
	public InputStreamReader(InputStream in, CharsetDecoder dec) {
        super(in);
        if (dec == null)
            throw new NullPointerException("charset decoder");
        sd = StreamDecoder.forInputStreamReader(in, this, dec);
    }
如果不指定,使用上一次的解码器
read(char cbuf[], int offset, int length)
调用解码器的读方法
 	 public int read(char cbuf[], int offset, int length) throws IOException {
        return sd.read(cbuf, offset, length);
    }
解码器的读方法如下
    public int read(char cbuf[], int offset, int length) throws IOException {
        int off = offset;
        int len = length;
        synchronized (lock) {
            ensureOpen();
            if ((off < 0) || (off > cbuf.length) || (len < 0) ||
                ((off + len) > cbuf.length) || ((off + len) < 0)) {
                throw new IndexOutOfBoundsException();
            }
            if (len == 0)
                return 0;
            int n = 0;
            if (haveLeftoverChar) {
                // Copy the leftover char into the buffer
                cbuf[off] = leftoverChar;
                off++; len--;
                haveLeftoverChar = false;
                n = 1;
                if ((len == 0) || !implReady())
                    // Return now if this is all we can produce w/o blocking
                    return n;
            }
            if (len == 1) {
                // Treat single-character array reads just like read()
                int c = read0();
                if (c == -1)
                    return (n == 0) ? -1 : n;
                cbuf[off] = (char)c;
                return n + 1;
            }
            return n + implRead(cbuf, off, off + len);
        }
    }
进一步调用implRead,在这里对数据进行解码,然后把解码后的内容拷贝到返回的buf中
    int implRead(char[] cbuf, int off, int end) throws IOException {
        assert (end - off > 1);
        CharBuffer cb = CharBuffer.wrap(cbuf, off, end - off);
        if (cb.position() != 0)
        cb = cb.slice();
        boolean eof = false;
        for (;;) {
        CoderResult cr = decoder.decode(bb, cb, eof);
        if (cr.isUnderflow()) {
            if (eof)
                break;
            if (!cb.hasRemaining())
                break;
            if ((cb.position() > 0) && !inReady())
                break;          // Block at most once
            int n = readBytes();
            if (n < 0) {
                eof = true;
                if ((cb.position() == 0) && (!bb.hasRemaining()))
                    break;
                decoder.reset();
            }
            continue;
        }
        if (cr.isOverflow()) {
            assert cb.position() > 0;
            break;
        }
        cr.throwException();
        }
        if (eof) {
        // ## Need to flush decoder
        decoder.reset();
        }
        if (cb.position() == 0) {
            if (eof)
                return -1;
            assert false;
        }
        return cb.position();
    }
四. BufferedReader
BufferedReader内部维持了一个Reader,缓冲输入, 需要输出时调用Reader的方法
 
                    
                     
                    
                 
                    
                
 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号