java IO(九):StreamEncoder补遗
这边再说三个方法:flushLeftoverChar(),writeBytes(),close()
一、flushLeftoverChar()
private void flushLeftoverChar(CharBuffer var1, boolean var2) throws IOException { if (this.haveLeftoverChar || var2) { if (this.lcb == null) { this.lcb = CharBuffer.allocate(2); } else { this.lcb.clear(); } if (this.haveLeftoverChar) { this.lcb.put(this.leftoverChar); } if (var1 != null && var1.hasRemaining()) { this.lcb.put(var1.get()); } this.lcb.flip(); while(this.lcb.hasRemaining() || var2) { CoderResult var3 = this.encoder.encode(this.lcb, this.bb, var2); if (var3.isUnderflow()) { if (this.lcb.hasRemaining()) { this.leftoverChar = this.lcb.get(); if (var1 != null && var1.hasRemaining()) { this.flushLeftoverChar(var1, var2); } return; } break; } if (var3.isOverflow()) { assert this.bb.position() > 0; this.writeBytes(); } else { var3.throwException(); } } this.haveLeftoverChar = false; } }
var1是字符缓冲区,var2调用时为false,leftoverChar与haveLeftoverChar为该类属性域。下面为流程图:
二、writeBytes():
此方法才是真正把数据输出至计算机的方法(之前只是存在缓冲区里,并未真正输出到计算机本地)
private void writeBytes() throws IOException { this.bb.flip(); int var1 = this.bb.limit(); int var2 = this.bb.position(); assert var2 <= var1; int var3 = var2 <= var1 ? var1 - var2 : 0; if (var3 > 0) { if (this.ch != null) { assert this.ch.write(this.bb) == var3 : var3; } else { this.out.write(this.bb.array(), this.bb.arrayOffset() + var2, var3); } } this.bb.clear(); }
这里先把字节缓冲区翻转(因为之前都是从字符缓冲区里往其中放数据,现在要取出来输出),然后判断bb中position和limit位置的合法性,若无错,则利用通道或是不使用通道输出(有通道则优先使用通道),输出后将bb清空以便下一次填充。
三、close():
其实我们可以看到,在implwrite()的有些情况和flushLeftoverChar中最后都没有直接使用writeBytes()进行输出,那么这时方法调用完后编码的字符还在字节缓冲区中,并未输出至本地,所以,使用write类输出流时,最后一定不能忘记关闭输出流,输出流的close()方法会将字节缓冲区中余下的数据输出至本地文件。如果不调用,则输出可能少数据或根本不会进行输出!下面举一个例子:
public class Test { public static void main(String[] args) { File file = new File("D:\\img\\test.txt"); try { OutputStreamWriter writer = new FileWriter(file,true); String s = "中文"; writer.write(s); //writer.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e){ e.printStackTrace(); } System.out.println(); } }
这里若将close注释掉,则运行后:
可以看到文本文档是空的,而调用close()后,在看该文本文档:
这时候便正常输出了。
public void close() throws IOException { synchronized(this.lock) { if (this.isOpen) { this.implClose(); this.isOpen = false; } } }
而close()方法本质是调用了implClose():
void implClose() throws IOException { this.flushLeftoverChar((CharBuffer)null, true); try { while(true) { CoderResult var1 = this.encoder.flush(this.bb); if (var1.isUnderflow()) { if (this.bb.position() > 0) { this.writeBytes(); } if (this.ch != null) { this.ch.close(); } else { this.out.close(); } return; } if (var1.isOverflow()) { assert this.bb.position() > 0; this.writeBytes(); } else { var1.throwException(); } } } catch (IOException var2) { this.encoder.reset(); throw var2; } }
可以看到该方法里又进行了一遍编码判断并全都调用了writeBytes()方法,把字节缓冲区里所有的内容全部输出,这就是为什么一定要调用close()的原因了。(该方法同时也会将leftoverChar输出,在方法开头有判断)