天天看點

(八)InputStreamReader及OutputStreamWriter

InputStreamReader的作用就是将位元組輸入流變為字元輸入流,底層的實作是靠StreamDecoder完成的。

public class InputStreamReader extends Reader {

    private final StreamDecoder sd;


    public InputStreamReader(InputStream in) {
        super(in);
        try {
            sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object
        } catch (UnsupportedEncodingException e) {
            // The default encoding should always be available
            throw new Error(e);
        }
    }


    public InputStreamReader(InputStream in, String charsetName)
        throws UnsupportedEncodingException
    {
        super(in);
        if (charsetName == null)
            throw new NullPointerException("charsetName");
        sd = StreamDecoder.forInputStreamReader(in, this, charsetName);
    }


    public InputStreamReader(InputStream in, Charset cs) {
        super(in);
        if (cs == null)
            throw new NullPointerException("charset");
        sd = StreamDecoder.forInputStreamReader(in, this, cs);
    }


    public InputStreamReader(InputStream in, CharsetDecoder dec) {
        super(in);
        if (dec == null)
            throw new NullPointerException("charset decoder");
        sd = StreamDecoder.forInputStreamReader(in, this, dec);
    }


    public String getEncoding() {
        return sd.getEncoding();
    }


    public int read() throws IOException {
        return sd.read();
    }


    public int read(char cbuf[], int offset, int length) throws IOException {
        return sd.read(cbuf, offset, length);
    }


    public boolean ready() throws IOException {
        return sd.ready();
    }

    public void close() throws IOException {
        sd.close();
    }
}
           

StreamDecoder在jdk源碼中并沒有開源,不過通過相應版本的openJDK可以看到StreamDecoder的源碼。

public int read() throws IOException {
        return read0();
    }
//讀取單個字元
private int read0() throws IOException {
        synchronized (lock) {

            // Return the leftover char, if there is one
            if (haveLeftoverChar) {
                haveLeftoverChar = false;
                return leftoverChar;
            }

            // Convert more bytes
            char cb[] = new char[];//至少讀取2個字元
            int n = read(cb, , );
            switch (n) {
            case -:
                return -;
            case ://保留多讀取的字元,以便下次使用
                leftoverChar = cb[];
                haveLeftoverChar = true;
                // FALL THROUGH
            case ://傳回讀取到的第一個字元
                return cb[];
            default:
                assert false : n;
                return -;
            }
        }
    }
//讀取字元數組
public int read(char cbuf[], int offset, int length) throws IOException {
        int off = offset;
        int len = length;
        synchronized (lock) {
            ensureOpen();
            if ((off < ) || (off > cbuf.length) || (len < ) ||
                ((off + len) > cbuf.length) || ((off + len) < )) {
                throw new IndexOutOfBoundsException();
            }
            if (len == )
                return ;

            int n = ;
            //傳回此前緩存的單個字元
            if (haveLeftoverChar) {
                // Copy the leftover char into the buffer
                cbuf[off] = leftoverChar;
                off++; len--;
                haveLeftoverChar = false;
                n = ;
                if ((len == ) || !implReady())
                    // Return now if this is all we can produce w/o blocking
                    return n;
            }
            //讀取單個字元
            if (len == ) {
                // Treat single-character array reads just like read()
                int c = read0();
                if (c == -)
                    return (n == ) ? - : n;
                cbuf[off] = (char)c;
                return n + ;
            }

            return n + implRead(cbuf, off, off + len);//讀取底層輸入流的函數
        }
    }
           

在read函數中,要求至少讀取2個字元,為什麼這樣設定呢?這跟Unicode字元集及utf-16編碼有關了,具體解釋可以參考Character的API文檔及參考文章使用 Java 語言進行 Unicode 代理程式設計。

OutputStreamWriter使用StreamEncoder進行字元到位元組的編碼,原理與上面類似。