栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java InputStream源码总结 InputStream源码注释翻译和解析中英文对照版

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java InputStream源码总结 InputStream源码注释翻译和解析中英文对照版

版本
JDK8(JDK1.8)

InputStream虚拟类源码重点
1.InputStream虚拟类实现 Closeable 接口,自然就具有 Closeable 接口特性

Closeable 源码可以看我这篇文章 Closeable

2.InputStream虚拟类只定义了一个虚拟方法abstract int read(),用于阻塞地读取一个字节,而该虚拟类的其他部分方法都使用该虚拟方法来实现,所以其子类只需要实现一个read()方法即可

3.InputStream虚拟类方法

方法名作用
abstract int read()阻塞地读取一个字节,返回0到255范围内的整数
int read(byte b[])有限循环阻塞地读取字节填满字节数组b,返回实际读取的字节数(遇到文件结尾或出错就无法填满,下面也一样)
int read(byte b[], int off, int len)有限循环阻塞地读取字节从字节数组b偏移量off处开始存放,最多读取len个字节,返回实际读取的字节数
byte[] readAllBytes()读取输入流所有字节存到字节数组中,最多读取2G的文件(由于字节数组长度有限)
int readNBytes(byte[] b, int off, int len)无限循环阻塞地读取字节从字节数组b偏移量off处开始存放,正常情况读取len个字节才返回,返回实际读取的字节数
long skip(long n)跳过并丢弃此输入流中的n字节数据,使用read()实现,效率较低
int available()返回可从此输入流读取(或跳过)的字节数的估计值
void close()关闭此输入流并释放与该流关联的所有系统资源
synchronized void mark(int readlimit)标记此输入流中的当前位置
synchronized void reset()将此流重新定位到上次对此输入流调用mark方法时的位置
boolean markSupported()测试此输入流是否支持标记mark和重置reset方法
long transferTo(OutputStream out)从该输入流使用read()读取所有字节,并按读取顺序将字节写入给定的输出流

long skip(long n) 原生实现的是RandomAccessFile类
RandomAccessFile源码可以看我这篇文章 RandomAccessFile

InputStream虚拟类源码

package java.io;

import java.util.Arrays;
import java.util.Objects;


public abstract class InputStream implements Closeable {

    // MAX_SKIP_BUFFER_SIZE is used to determine the maximum buffer size to
    // use when skipping.
    // 最大跳过缓冲区大小用于确定跳过时要使用的最大缓冲区大小。
    private static final int MAX_SKIP_BUFFER_SIZE = 2048;

    // 默认缓存区大小
    private static final int DEFAULT_BUFFER_SIZE = 8192;

    
    public abstract int read() throws IOException;

    
    public int read(byte b[]) throws IOException {
        return 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) {
            // 直接返回-1
            return -1;
        }
        // 如果读取到该字节,设置到字节数组b中
        b[off] = (byte)c;

        // 循环len-1次
        int i = 1;
        try {
            for (; i < len ; i++) {
                // 每次读取一个字节
                c = read();
                // 如果遇到文件结尾跳出循环
                if (c == -1) {
                    break;
                }
                // 如果该字节成功读取,将其设置到字节数组中
                b[off + i] = (byte)c;
            }
        } catch (IOException ee) {
        }
        return i;
    }

    
    private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;

    
    // 读取所有字节到字节数组中,除非文件大于2G,不然可以容纳下
    public byte[] readAllBytes() throws IOException {
        // 创建一个缓冲池字节数组 8KB大小
        byte[] buf = new byte[DEFAULT_BUFFER_SIZE];
        // 容量为缓冲字节数组长度
        int capacity = buf.length;
        int nread = 0;
        int n;
        for (;;) {
            // read to EOF which may read more or less than initial buffer size
            // 读取到EOF,该EOF可以读取大于或小于初始缓冲区大小
            // EOF即结尾
            // 循环进行这个操作,直到把缓冲字节数组填满
            while ((n = read(buf, nread, capacity - nread)) > 0)
                //由于n不确定,每次读取的字节也不确定
                //根据读取的字节确定偏移量nread和
                //现在要读取的剩余字节长度capacity - nread
                nread += n;

            // if the last call to read returned -1, then we're done
            // 如果最后一个read调用返回-1,那么我们就完成了
            if (n < 0)
                break;

            // need to allocate a larger buffer
            // 需要分配更大的缓冲区
            // 如果上面缓存区填满了,仍然有数据没有读取完,就进行缓存区扩容操作
            // 如果容量小于 最大缓存区容量 - 容量 ,即 capacity <= MAX_BUFFER_SIZE / 2
            // 即小于最大容量的二分之一
            if (capacity <= MAX_BUFFER_SIZE - capacity) {
                // 进行二倍扩容
                capacity = capacity << 1;
            } else {
                // 如果扩容前容量已经等于最大缓冲池大小,则抛出异常
                if (capacity == MAX_BUFFER_SIZE)
                    throw new OutOfMemoryError("Required array size too large");
                // 将容量设为最大缓冲池大小
                capacity = MAX_BUFFER_SIZE;
            }
            // 复制数组进行扩容
            buf = Arrays.copyOf(buf, capacity);
        }
        // 如果容量等于偏移量,说明字节数组已经被填满,可以直接返回
        // 如果容量大于偏移量,说明字节数组有空闲空间,需要复制缩容
        return (capacity == nread) ? buf : Arrays.copyOf(buf, nread);
    }

    
    public int readNBytes(byte[] b, int off, int len) throws IOException {
        // 如果b为空,抛出异常
        Objects.requireNonNull(b);
        // 如果索引越界,抛出异常
        if (off < 0 || len < 0 || len > b.length - off)
            throw new IndexOutOfBoundsException();
        // n为读取的字节总数
        int n = 0;
        // 如果读取字节数小于要求的读取字节数,则循环不断读取
        while (n < len) {
            // count返回实际读取字节数
            // 每次读取的偏移量 off + n 和要读取的字节数 len - n 都得重新设置
            int count = read(b, off + n, len - n);
            // 如果遇到文件结尾,则退出循环
            if (count < 0)
                break;
            // 更新读取字节总数
            n += count;
        }
        return n;
    }

    
    public long skip(long n) throws IOException {

        // 剩余要跳过的字节 remaining
        long remaining = n;
        int nr;

        // 如果要跳过的字节小于n
        if (n <= 0) {
            return 0;
        }

        // 如果要跳过的字节数大于2KB,则取2KB
        int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining);
        // 跳过的字节缓冲数组
        byte[] skipBuffer = new byte[size];
        // 当要跳过的剩余字节大于0
        while (remaining > 0) {
            // 使用read(.) 方法来达到跳过字节目的,效率比较低
            // nr为本次read实际读取到的字节数,也就是实际跳过的字节数
            nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
            if (nr < 0) {
                break;
            }
            // 更新要跳过的剩余字节数
            remaining -= nr;
        }

        // 返回实际跳过的字节数
        // 即期望跳过的字节数 - 剩余要跳过的字节数
        return n - remaining;
    }

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

    
    public boolean markSupported() {
        return false;
    }

    
    public long transferTo(OutputStream out) throws IOException {
        // 如果out为空,则抛出异常
        Objects.requireNonNull(out, "out");
        // 总共传输给输出流的字节
        long transferred = 0;
        // 创建缓冲数组,默认大小为8KB
        byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
        // 每次读取的字节数
        int read;
        // 如果每次都读取到了字节,并放置在缓冲数组中
        while ((read = this.read(buffer, 0, DEFAULT_BUFFER_SIZE)) >= 0) {
            // 则将该缓冲数组中有效数据,写入到输出流中
            out.write(buffer, 0, read);
            // 更新总共传输给输出流的字节数
            transferred += read;
        }
        // 返回总共传输给输出流的字节
        return transferred;
    }
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/327468.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号