美文网首页
Java IO入门(含源码解析)

Java IO入门(含源码解析)

作者: 橙味菌 | 来源:发表于2019-10-07 17:53 被阅读0次

    Java IO

    Java的输入输出流,用于和程序外部交换数据。Java的IO是通过流式传输的

    流的链接机制

    可将一个流和另一个流首尾相接,以将输入数据转换成相应的输出数据

    IO流接口

    Java的IO流接口

    对应抽象类
    输入流 InputStream/Reader
    输出流 OutputStream/Writer
    字节流 InputStream/OutputStream
    字符流 Reader/Writer

    InputStream

    字节输入流,以字节为单位从程序外部获取数据
    API

    类型 作用 API
    统计 流内有效字节数 available()
    读出一个字节 read()
    读出一定长度字节 read(byte[],int offset,lenght)
    跳过 跳过一定长度字节开始读 skip(long n)
    回溯 能否标记 markSupported
    标记当前读的位置 mark(int readlimit)
    回到标记开始读 reset
    关闭 清空缓冲区 flush()
    关闭流 close()

    InputStream继承关系类图

    InputStream继承类图

    真是令人望而生畏!

    InputStream节选继承关系类图

    InputStream继承类图-节选

    节选了几个重要输入流实现类

    从类图可以清楚地看到,左边三个实现类有InputStream的引用,意味着他们内部有流的链接。而右侧几个实现类则最多只能链接同类型的输入流

    实现类 描述
    ObjectInputSteam 从其他InputStream中读出Object
    SequenceInputStream 持有一组InputStream,读完一个换一个
    FilterInputStream 从其他InputStream过滤输入数据并读出
    StringInptStream 从字符串或其他String输入流中读出字节数据
    ByteArrayInputStream 从字节数组中读出字节数据
    PipedInputStream
    FileInputStream 从文件中读字节数据

    实现类源码解析

    简略解析,其中ObjectInputStream和PipedInputStream由于篇幅较长,以后再解析

    ByteArrayInputStream

    从字节数组中读出字节数据
    成员变量

    成员变量 含义
    byte buf[] 流的数据缓冲
    int pos 当前读的位置
    int mark = 0 标记的位置
    int count 缓冲长度

    构造函数

    //构造函数提供字节数组源,直接复制到流的缓冲区,初始化下一次读的位置以及缓冲区大小
    public ByteArrayInputStream(byte buf[]) {
        this.buf = buf;
        this.pos = 0;
        this.count = buf.length;
    }
    

    读数据

    //缓冲无可用数据返回-1,有就读一个字节放在int的后8位返回并更新下一次读的位置
    public synchronized int read() {
        return (pos < count) ? (buf[pos++] & 0xff) : -1;
    }
    //缓冲无可用数据返回-1,否则复制到参数提供的数组中,返回实际复制的字节数
    public synchronized int read(byte b[], int off, int len) {
        if (b == null) {
            throw new NullPointerException();
        } else if (off < 0 || len < 0 || len > b.length - off) {
            throw new IndexOutOfBoundsException();
        }
    
        if (pos >= count) {
            return -1;
        }
    
        int avail = count - pos;
        if (len > avail) {
            len = avail;
        }
        if (len <= 0) {
            return 0;
        }
        System.arraycopy(buf, pos, b, off, len);
        pos += len;
        return len;
    }
    

    跳着读

    //下次读的位置+n,如果超过缓冲区尾部则设为缓冲区尾部
    public synchronized long skip(long n) {
        long k = count - pos;
        if (n < k) {
            k = n < 0 ? 0 : n;
        }
    
        pos += k;
        return k;
    }
    

    回溯读

    //支持mark和reset
    public boolean markSupported() {
        return true;
    }
    //设置标记为下一次要读的位置
    public void mark(int readAheadLimit) {
        mark = pos;
    }
    //设置下一次要读的位置为标记
    public synchronized void reset() {
        pos = mark;
    }
    
    StringInputStream

    从字符串或其他String输入流中读出字节数据,继承自ReaderInputStream,持有该一个Reader对象用于读取字符串,然后拆分字符为字节数据读出

    //字符输入流
    private Reader in;
    //编码
    private String encoding;
    //字符中读剩下的字节的缓冲
    private byte[] slack;
    //缓冲起始位
    private int begin;
    
    public synchronized int read() throws IOException {
        if (this.in == null) {
            throw new IOException("Stream Closed");
        } else {
            byte result;
            //有上次读剩的缓冲,从缓冲读
            if (this.slack != null && this.begin < this.slack.length) {
                result = this.slack[this.begin];
                if (++this.begin == this.slack.length) {
                    this.slack = null;
                }
                //无缓冲,从字符输入流读一个字符到缓冲,返回缓冲第一位
            } else {
                byte[] buf = new byte[1];
                if (this.read(buf, 0, 1) <= 0) {
                    return -1;
                }
    
                result = buf[0];
            }
    
            return result & 255;
        }
    }
    
    FileInputStream

    文件输入流,从文件中读取字节数据

    public int read() throws IOException {
        return read0();
    }
    //需要本地方法读取文件
    private native int read0() throws IOException;
    
    SequenceInputStream

    序列字节输入流,持有一组字节输入流,依次进行读出,读完一个切换一个
    成员变量

    成员变量 含义
    Enumeration<? extends InputStream> e 持有的字节输入流
    InputStream in 当前读的字节输入流

    read实现

    public int read() throws IOException {
        while (in != null) {
            //读当前InputStream,读完了切换
            int c = in.read();
            if (c != -1) {
                return c;
            }
            nextStream();
        }
        return -1;
    }
    
    final void nextStream() throws IOException {
        //关闭现在的输入流
        if (in != null) {
            in.close();
        }
        //切换下一个输入流
        if (e.hasMoreElements()) {
            in = (InputStream) e.nextElement();
            if (in == null)
                throw new NullPointerException();
        }
        else in = null;
    
    }
    
    FilterInputStream

    FilterInputStream使用代理模式,封装了一个字节输入流对象,在重写的方法中通过调用字节输入流对象的方法读取数据,再通过过滤代码(由子类重写read方法添加)实现对输入数据的过滤

    //持有的字节输入流对象
    protected volatile InputStream in;
    //构造函数
    protected FilterInputStream(InputStream in) {
        this.in = in;
    }
    //读取一个字节
    public int read() throws IOException {
        return in.read();
    }
    

    OutputStream

    字节输出流,以字节为单位输出
    API

    类型 作用 API
    写入一个字节 write(int)
    写入一个字节数组 read/write(byte[],int offset,lenght)
    关闭 清空缓冲区 flush()
    关闭流 close()

    Reader

    字符输入流,以字符为单位从程序外部获取数据
    API

    类型 作用 API
    读出一个字符读出一个字节 read()
    读出一定长度字符 read/write(char[],offset,len)
    跳过 跳过一定长度字节开始读 skip(long n)
    回溯 能否标记 markSupported
    标记当前读的位置 mark(int readlimit)
    回到标记开始读 reset
    关闭 清空缓冲区 flush()
    关闭流 close()

    Writer

    API

    类型 作用 API
    写入一定长度字符 append/write(char[],offset,len)
    写入一个字符串 append/write(String s)
    写入一个字符串的指定区间 append/write(String s,offset,len)
    关闭 关闭流 close
    清空流内缓冲 flush()

    相关文章

      网友评论

          本文标题:Java IO入门(含源码解析)

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