java IO笔记(InputStream/OutputSteram)

本文详细介绍了Java IO包中的InputStream和OutputStream两个基本类。通过对源码的解析,讲解了读取和写入操作的基本方法及其实现原理。

本篇讲述的内容是java io中的InputStream和OutputStream。

我们知道流是一种抽象的概念,抽象了输入输出设备。在java中,所有的流对象都位于java.io包中,其中有4个流是特殊的,通过它们可以衍生出所有的流对象,它们分别是InputStream/OutputStream和Reader/Writer。它们是通过流中数据的单位来区分的。本次讲述的是其中的字节流,InputStream和OutputStream。

这四个基类都是抽象类,其中定义了一些流所具备的方法,下面将贴出InputStream和OutputStream的源码,来进行分析:

InputStream.java:

package java.io;

public abstract class InputStream implements Closeable {

    //声明了一个最终常量,MAX_SKIP_BUFFER_SIZE,该常量限制了下面skip方法中所创建的buffer缓冲区的最大容量。
    private static final int MAX_SKIP_BUFFER_SIZE = 2048;

    /**
     *从流中读取一个byte的数据,并返回一个int值,如果到达了流的尾端或者没有数据可读,将返回-1。
     */
    public abstract int read() throws IOException;

    /**
     *一个带参的read方法,传入一个byte数组,内部调用带3个参数的read方法,用整个数组去读取数据。
     */
    public int read(byte b[]) throws IOException {
        return read(b, 0, b.length);
    }

    /**
     * 一个带3个参数的read方法,第一个参数是存放数据的数组,第二个参数是开始存放数据的起点,第三个参数是数据存储的长度。
     *返回一个int值,该值为实际成功读取的byte数据的次数。如过没有成功读取到有用的数据,则返回-1。
     */
    public int read(byte b[], int off, int len) throws IOException {
	//对传入参数的安全监测。如果传入数组为空报空指针异常,如果读取起点、读取长度小于0或者读取起点加上读取长度大于数组本身长度抛越界异常,如果读取长度
	//为0,则返回0,表示读取了0个数据
        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;

	//通过循环读取,为byte数组赋值,同时每次循环,使得i+1,最终返回i的值。
        int i = 1;
        try {
            for (; i < len ; i++) {
                c = read();
                if (c == -1) {
                    break;
                }
                b[off + i] = (byte)c;
            }
        } catch (IOException ee) {
        }
        return i;
    }

    /**
     * 一个带参的skip方法,参数为一个long型数据,表示跳跃读取的长度,返回一个long型数据,表示实际已经跳过的数据长度。
     */
    public long skip(long n) throws IOException {

        long remaining = n;
        int nr;

        if (n <= 0) {
            return 0;
        }

	//建立一个最大容量为2048的byte数组,内部调用带3个参数的read方法来起到跳过的作用。每读取一次,都将remaining减去读取过的值,最终通过n-r来得到实际跳
	//过的数据长度。
        int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining);
        byte[] skipBuffer = new byte[size];
        while (remaining > 0) {
            nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
            if (nr < 0) {
                break;
            }
            remaining -= nr;
        }

        return n - remaining;
    }

    /**
     * 来获取流中实际可以读取的数据的总长度,该方法应该被子类重写,应为InputStream中该方法的返回值永远为0。当然该方法的返回值不一定是准确的,有兴趣的朋友
     *可以自行查阅相关资料,java源码中给出的官方注释也解释的蛮清楚的,此处就不再多说了。
     */
    public int available() throws IOException {
        return 0;
    }

    /**
     * 该方法用于关闭流
     */
    public void close() throws IOException {}

    /**
     *该方法用于标记流当前的读取位置
     */
    public synchronized void mark(int readlimit) {}

    /**
     *该方法用于将流的读取位置返回至标记处
     */
    public synchronized void reset() throws IOException {
        throw new IOException("mark/reset not supported");
    }

    /**
     *该方法用于返回当前流是否支持标记功能,InputStream永远返回为false。
     */
    public boolean markSupported() {
        return false;
    }

}

OutputStream.java:

package java.io;

public abstract class OutputStream implements Closeable, Flushable {
    /**
     * 一个带参的write方法,传入的参数为一个int型的值,该方法每次写出一个byte数据,传入的int型数据b为要写出的数据。
     */
    public abstract void write(int b) throws IOException;

    /**
     *一个带参的write方法,传入的参数为一个byte型数组,该方法将数组中的所有数据写出。
     */
    public void write(byte b[]) throws IOException {
        write(b, 0, b.length);
    }

    /**
     * 一个带三个参数的write方法,第一个参数为一个byte型数组,其中包含了写出数据,第二个参数为写出的起始位置,第三个参数为写出数据的长度。
     */
    public void write(byte b[], int off, int len) throws IOException {
        //对传入参数的安全监测。如果传入数组为空报空指针异常,如果写出起点、写出长度小于0或者写出起点大于数组本身长度则抛越界异常,如果写出长度
	//为0,则返回0,表示写出了0个数据

        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]);
        }
    }

    /**
     * 该方法用于将缓存区中的数据写入目的地。
     */
    public void flush() throws IOException {
    }

    /**
     * 该方法用于关闭当前流
     */
    public void close() throws IOException {
    }

}

以上为本篇内容。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

moonfish0607

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值