• 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输出,在方法开头有判断)

  • 相关阅读:
    IDEA插件Mybatis logs不打印Mybatis 或者 Mybatis -plus 的SQL日志
    JRebel启动报错,但不影响正常运行JRebel: ERROR Class 'org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor' could not be processed by .....
    自增运算符 ++
    赋值操作符 =
    逻辑操作符
    算术操作符
    变量类型
    打印,注释,空白
    Java开发环境的安装和配置
    java应用背景
  • 原文地址:https://www.cnblogs.com/MYoda/p/11214607.html
Copyright © 2020-2023  润新知