美文网首页Java IO流源码学习
Java源码学习--InputStream、OutputStre

Java源码学习--InputStream、OutputStre

作者: 慕北人 | 来源:发表于2019-08-28 22:52 被阅读0次

    Java源码学习--InputStream、OutputStream、Reader、Writer

    Java中的集合类就先告一段落了,之后会学习一下Java中的IO类的源代码。由于Java中IO类都是InputStream、OutputStream、Reader、Writer的实现类,所以这里先来看看这四个类的源代码。

    一、InputStream类

    该类实现了Closeable几口,不过并没有实现close()方法

    InputStream需要认真查看的似乎只有read()、read(byte b[])、read(byte b[], int off, int len)三个方法

    1. read()方法

    关于该方法,InputStream中规定,该方法返回数据源中下一个字节的int表示,当到达末尾的时候返回-1

    在InputStream中该方法是一个抽象方法,等待着子类去实现。

    2. read(byte b[], int off, int len)方法

    这里跳过read(byte b[])方法的原因是因为该方法的实现就是调用read(b, 0, b.length)

    public int read(byte b[], int off, int len) throws IOException {
        if (b == null) {
            throw new NullPointerException();
        } else if (off < 0 || len < 0 || len > b.length - off) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return 0;
        }
    
        int c = read();
        if (c == -1) {
            return -1;
        }
        b[off] = (byte)c;
    
        int i = 1;
        try {
            for (; i < len ; i++) {
                c = read();
                if (c == -1) {
                    break;
                }
                b[off + i] = (byte)c;
            }
        } catch (IOException ee) {
        }
        return i;
    }  
    

    该方法的核心就是:使用read()方法逐个字节地读取数据源中的数据,放入到参数字节数组中,直到数据源的末尾;如果返回值为-1,说明数据源中根本没有数据,否则返回读取的字节个数(一般小于等于len参数)。

    二、OutputStream

    该类实现了Closeable接口和Flushable接口,前者提供close()方法、后者提供flush()方法,不过OutputStream并没有实现这两个方法。

    同InputStream一样,OutputStream方法值得去分析的似乎也只有write(int byte)、write(byte b[])、write(byte b[], int off, int len)

    1. write(int byte)

    该方法的作用是将参数写入到output stream中去,有一点需要澄清的是,参数是一个int类型,但并不是真的写入一个int类型,只会写入其低8比特位

    2. write(byte b[], int off, int len)

    同InputStream一样,这里跳过write(byte b[])的原因也是其回调了write(b, 0, b.length)

    该方法的作用是将参数b[]中是数据从off开始,len个写入到output stream中去。

    public void write(byte b[], int off, int len) throws IOException {
        if (b == null) {
            throw new NullPointerException();
        } else if ((off < 0) || (off > b.length) || (len < 0) ||
                   ((off + len) > b.length) || ((off + len) < 0)) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return;
        }
        for (int i = 0 ; i < len ; i++) {
            write(b[off + i]);
        }
    }  
    

    三、Reader

    该类和InputStream相对应,只不过是按字符单位处理数据

    Reader实现了Readable接口和Closeable接口,前者是为了适配nio,提供了一个read(java.nio.CharBuffer target)方法。

    1. 构造器

    Reader较InputStream有一个很大的不同是,其提供了支持同步的lock属性:lock

    protected Reader() {
        this.lock = this;
    }  
    
    protected Reader(Object lock) {
        if (lock == null) {
            throw new NullPointerException();
        }
        this.lock = lock;
    }  
    

    2. read()方法

    Reader中的read()方法和read(byte b[], int off, int len)方法的关系同InputStream中是相反的,read()方法是通过后者实现的,而不是同InputStream中那样,后者是调用read()方法来实现数据的读取的。

    public int read() throws IOException {
        char cb[] = new char[1];
        if (read(cb, 0, 1) == -1)
            return -1;
        else
            return cb[0];
    }  
    

    这样一来对像我这样的强迫症很不适应,每次读取一个数据都需要new 一个char数组来,感觉好亏啊。

    3. read(byte b[], int off, int len)

    上面提到,该方法的地位等同于InputStream中的read()方法,因此,Reader并没有为该方法提供方法实现,子类需要自己去实现它。

    四、Writer

    同样,Writer和OutputStream相对应,其实现了Closeable、Flushable两个接口。

    1. 构造器

    Writer有一个char数组用来缓存:char[] writeBuffer

    protected Writer() {
        this.lock = this;
    }  
    
    protected Writer(Object lock) {
        if (lock == null) {
            throw new NullPointerException();
        }
        this.lock = lock;
    }  
    

    2. write(int c)方法

    该方法负责往输出流中写入一个字符的内容,同样,由于参数是一个int类型的数据,这里只会写入参数的低16比特位

    public void write(int c) throws IOException {
        synchronized (lock) {
            if (writeBuffer == null){
                writeBuffer = new char[WRITE_BUFFER_SIZE];
            }
            writeBuffer[0] = (char) c;
            write(writeBuffer, 0, 1);
        }
    }  
    

    同样可以看到,在Writer中,write()方法是通过write(char[] c, int off, int len)实现的;可以看到在进行写入操作的时候,Writer使用了synchronized关键字,意味着同时只有一个Writer可以进行写入操作

    3. write(char[] c, int off, int len)

    该方法和Reader中一样,也是供子类来实现。

    4. write(String s)和write(String s, int off, int len)方法

    由于String的特殊性,其可以看作一个char数组,因此Writer专门为其提供了这两个方法做处理。

    public void write(String str) throws IOException {
        write(str, 0, str.length());
    }  
    
    public void write(String str, int off, int len) throws IOException {
        synchronized (lock) {
            char cbuf[];
            if (len <= WRITE_BUFFER_SIZE) {
                if (writeBuffer == null) {
                    writeBuffer = new char[WRITE_BUFFER_SIZE];
                }
                cbuf = writeBuffer;
            } else {    // Don't permanently allocate very large buffers.
                cbuf = new char[len];
            }
            str.getChars(off, (off + len), cbuf, 0);
            write(cbuf, 0, len);
        }
    }  
    

    可见,其本质还是调用的write(char[] c, int off, int len)方法,有一个疑问:这里的synchronized关键字是否是没必要的,这里有不涉及到写入操作,而write方法中本来就有synchronized关键字的啊?

    相关文章

      网友评论

        本文标题:Java源码学习--InputStream、OutputStre

        本文链接:https://www.haomeiwen.com/subject/lavvectx.html