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進行字元到位元組的編碼,原理與上面類似。