其實這三個輸出流,就是對應那三個輸入流的。
和那三個輸入流一樣,這三個流在字符輸出上也密切相關。
一、FileWriter
和輸入流一樣,也是只有幾個對應文件系統的構造方法,這里不再贅述。
二、OutputStreamWriter
和輸入流一樣,也是通過傳入的OutputStream流對StreamEncoder進行初始化,append在OutputStream流中已指定。
三、StreamEncoder
這才是字符輸出流的關鍵類(同理在實際使用中也最好使用BufferedWriter進行包裝)
這個類和StreamDecoder長得非常類似,我們來比較一下:
1)屬性域
StreamEncoder
private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192; //確保流是打開狀態否則無法輸入輸出 private volatile boolean isOpen; //字符集 private Charset cs; //編碼器 private CharsetEncoder encoder; //字節緩沖區 private ByteBuffer bb; //輸出流 private final OutputStream out; //信道,對於輸入流,緩沖區從信道中取數據,對於輸出流,緩沖區輸出內容到信道(應該是這樣,信道這個概念還未理解) private WritableByteChannel ch; //為保證讀入的字符不亂嗎,則每次要讀入兩個字符 private boolean haveLeftoverChar; private char leftoverChar; //字符緩沖區——專用於左側字符操作 private CharBuffer lcb;
StreamDecoder
//定義兩個表示字節緩沖區大小的整型常量,最小為32,默認為8192 private static final int MIN_BYTE_BUFFER_SIZE = 32; private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192; //表示流是否被打開的布爾型變量 private volatile boolean isOpen; //在read里用到,read方法返回一個字符,但實際上是讀取2個字符,剩余的一個字符會保存到leftoverChar里,haveLeftoverChar表示是否有這個剩余多出來的字符。 private boolean haveLeftoverChar; private char leftoverChar; //這個和下面的ReadableByteChannel意思是信道,但還不知道有什么用 private static volatile boolean channelsAvailable = true; //字符集 private Charset cs; //解碼器 private CharsetDecoder decoder; //字節緩沖對象 private ByteBuffer bb; //字節輸入流 private InputStream in; private ReadableByteChannel ch;
2)構造方法
private StreamEncoder(OutputStream var1, Object var2, Charset var3) { this(var1, var2, var3.newEncoder().onMalformedInput(CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE)); } private StreamEncoder(OutputStream var1, Object var2, CharsetEncoder var3) { super(var2); this.isOpen = true; this.haveLeftoverChar = false; this.lcb = null; this.out = var1; this.ch = null; this.cs = var3.charset(); this.encoder = var3; if (this.ch == null) { this.bb = ByteBuffer.allocate(8192); } } private StreamEncoder(WritableByteChannel var1, CharsetEncoder var2, int var3) { this.isOpen = true; this.haveLeftoverChar = false; this.lcb = null; this.out = null; this.ch = var1; this.cs = var2.charset(); this.encoder = var2; this.bb = ByteBuffer.allocate(var3 < 0 ? 8192 : var3); }
和StreamDecoder區別不大,不再贅述
3)forOutputStreamWriter()
public static StreamEncoder forOutputStreamWriter(OutputStream var0, Object var1, String var2) throws UnsupportedEncodingException { String var3 = var2; if (var2 == null) { var3 = Charset.defaultCharset().name(); } try { if (Charset.isSupported(var3)) { return new StreamEncoder(var0, var1, Charset.forName(var3)); } } catch (IllegalCharsetNameException var5) { } throw new UnsupportedEncodingException(var3); } public static StreamEncoder forOutputStreamWriter(OutputStream var0, Object var1, Charset var2) { return new StreamEncoder(var0, var1, var2); } public static StreamEncoder forOutputStreamWriter(OutputStream var0, Object var1, CharsetEncoder var2) { return new StreamEncoder(var0, var1, var2);
也和StreamDecoder區別不大。
4)write()
相較StreamDecoder的read()方法,write()方法要簡單許多,就是直接判斷offset和len的合法性,然后調用implWrite()
public void write(int var1) throws IOException { char[] var2 = new char[]{(char)var1}; this.write((char[])var2, 0, 1); } public void write(char[] var1, int var2, int var3) throws IOException { synchronized(this.lock) { this.ensureOpen(); if (var2 >= 0 && var2 <= var1.length && var3 >= 0 && var2 + var3 <= var1.length && var2 + var3 >= 0) { if (var3 != 0) { this.implWrite(var1, var2, var3); } } else { throw new IndexOutOfBoundsException(); } } } public void write(String var1, int var2, int var3) throws IOException { if (var3 < 0) { throw new IndexOutOfBoundsException(); } else { char[] var4 = new char[var3]; var1.getChars(var2, var2 + var3, var4, 0); this.write((char[])var4, 0, var3); } }
上下兩個方法本質就是調用中間的write(char[] var1,int var2,int var3)
對於最上面的方法,是將單個字符轉成字符數組,然后傳入中間方法;對於下面的方法,是將字符串轉成字符數組,再傳入中間方法。
中間方法var1便是那個字符數組,var2可以理解為offset,var3可以理解為length。
5)implWrite(char[] cbuf, int offset, int length)
void implWrite(char[] var1, int var2, int var3) throws IOException { CharBuffer var4 = CharBuffer.wrap(var1, var2, var3); if (this.haveLeftoverChar) { this.flushLeftoverChar(var4, false); } while(var4.hasRemaining()) { CoderResult var5 = this.encoder.encode(var4, this.bb, false); if (var5.isUnderflow()) { assert var4.remaining() <= 1 : var4.remaining(); if (var4.remaining() == 1) { this.haveLeftoverChar = true; this.leftoverChar = var4.get(); } break; } if (var5.isOverflow()) { assert this.bb.position() > 0; this.writeBytes(); } else { var5.throwException(); } } }
flushLeftoverChar()和writeBytes()將在(八)中說到。