您的当前位置:首页正文

【杂记】java 读取未知文件大小,实现byte[]数组的动态扩容

2024-11-29 来源:个人技术集锦

小红:小明我这边有一个位置大小文件,需要导入到一个byte数组中,但是自己定义的byte数组如果太小,可能导入的文件不全,会丢失部分数据,如果定义的数组大小太大,会导致内存的浪费,我该如何处理?
小明:对于这种未知文件大小的读取,我们需要在读取的时候,对数组进行动态的扩容,以确保文件能完整的读入。
小红:那该如何做?
小明:
总体的思路如下:

代码源码来源于Files.readAll()方法


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

    /**
     * 该方法主要是对未知文件大小的流,实现动态扩展byte[]大小
     *
     * @param source      文件输入流
     * @param initialSize byte[]数组初始化大小
     * @return 返回文件流的byte[]
     * @throws IOException 流读取会产生的IO异常
     */
    public static byte[] read(InputStream source, int initialSize) throws IOException {
        int capacity = initialSize;
        //①定义一个初始化的byte[]
        byte[] buf = new byte[capacity];
        //②流读取到byte[]的位置
        int nread = 0;
        int n;
        //③死循环,读流
        for (; ; ) {
            //④将当前流读到初始化的byte[]中,read参数(读取的byte[],byte[]的起始位置,读取的长度),返回的当前读取的流的位置
            while ((n = source.read(buf, nread, capacity - nread)) > 0) {
                //⑤将当前流读取的位置,赋值与流读取的byte[]的位置
                nread += n;
            }
            //⑥判断n当前流的位置,当n小于0时或者流读取的位置小于0时,表示流以及读完,退出当前死循环
            if (n < 0 || (n = source.read()) < 0) break;
            //⑦判断当byte[]的大小,当前值小于等于(最大byte的buffer的值-当前byte[]的大小)⑪⑫⑬⑭⑮⑯
            if (capacity <= MAX_BUFFER_SIZE - capacity) {
                //初始值重新赋值,在当前值二进制值向左移一位返回值和我们自己定义的buffer的大小之前选择最大的值
                capacity = Math.max(capacity << 1, BUFFER_SIZE);
            } else {
                //⑧当前byte[]的大小值,大于(最大byte的buffer的值-当前byte[]的大小)
                //⑨先判断当前值是否等于最大byte的buffer的值,等于就抛出内存溢出异常,结束当前进程
                if (capacity == MAX_BUFFER_SIZE){
                    throw new OutOfMemoryError("Required array size too large");
                }
                //⑩否则将最大值赋予byte[]的大小的值
                capacity = MAX_BUFFER_SIZE;
            }
            //⑪将当前byte[]数组进行copy,copy参数(需要copy的byte[],初始化的大小)
            //源码里面查看,在数组copy的过程中,会在出现的大小值和需要copy数组的大小值进行最小选取,选取最小值为返回数组的大小
            buf = Arrays.copyOf(buf, capacity);
            //⑫在数组的末尾添加最后结束符
            buf[nread++] = (byte) n;
        }
        //⑬判断最终的数组的大小是否和流读取的最后位置一样,如果一致返回当前数组,否则返回copy的新数组
        return (capacity == nread) ? buf : Arrays.copyOf(buf, nread);
    }

显示全文