美文网首页Java 杂谈JAVA后端架构
踩坑笔记 >> InputStream.read(b

踩坑笔记 >> InputStream.read(b

作者: 阅历笔记 | 来源:发表于2019-05-24 17:04 被阅读1次

    写在前面


    在Java中流的一系列操作,可能会感到既熟悉又陌生。熟悉是因为很基础且出镜率很高,陌生对大多数程序员平时工作中很少写相关的代码。

    ~~ 我是很少写~~

    回归正题,本章我不不是探讨流,主要来说下造成‘标题’问题的原因。

    问题很简单,稍微看下源码或者debug下就可以找到问题所在,这是一些细节问题,既然出现了在此做下记录,给自己一个警惕。

    场景引入


    今天微信上突然收到前同事一段这样的问题描述

    在读取文件时如果文件为空、导致进入while死循环,

    并附上一段代码。

    /**
         * 将文件数据流写入到zip流中
         * 
         * @param fileName
         * @param inputStream
         * @param outputStream
         * @throws IOException
         */
        public static void zipInputStream(String fileName, InputStream inputStream, ZipOutputStream outputStream)
                throws IOException {
            try {
                BufferedInputStream bInStream = new BufferedInputStream(inputStream);
                outputStream.putNextEntry(new ZipEntry(fileName));
                byte[] buffer = new byte[inputStream.available()];
                int r = 0;
                while ((r = bInStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, r);
                }
                outputStream.closeEntry();
            } catch (IOException e) {
                throw e;
            } finally {
                if (null != inputStream) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        throw e;
                    }
                }
            }
        }
    

    咋一看这段代码也没啥问题!

    我们一点点的来分析下

    首先陷入while死循环的条件bInStream.read(buffer)) != -1

    while ((r = bInStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, r);
    }
    

    看下源码中的描述,

    /**
         * Reads up to <code>len</code> bytes of data from this input stream
         * into an array of bytes. If <code>len</code> is not zero, the method
         * blocks until some input is available; otherwise, no
         * bytes are read and <code>0</code> is returned.
         * <p>
         * This method simply performs <code>in.read(b, off, len)</code>
         * and returns the result.
         *
         * @param      b     the buffer into which the data is read.
         * @param      off   the start offset in the destination array <code>b</code>
         * @param      len   the maximum number of bytes read.
         * @return     the total number of bytes read into the buffer, or
         *             <code>-1</code> if there is no more data because the end of
         *             the stream has been reached.
         * @exception  NullPointerException If <code>b</code> is <code>null</code>.
         * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
         * <code>len</code> is negative, or <code>len</code> is greater than
         * <code>b.length - off</code>
         * @exception  IOException  if an I/O error occurs.
         * @see        java.io.FilterInputStream#in
         */
        public int read(byte b[], int off, int len) throws IOException {
            return in.read(b, off, len);
        }
    

    上面描述有这么一段,如果byte[]数组的len为0则不做任何操作直接返回0。

    看到这问题基本就可以定位了,在看代码中byte[]的定义。

    byte[] buffer = new byte[inputStream.available()];
    

    看到这小伙们就笑了inputStream.available(),你读的是一个空文件可不是为0。

    /**
         * Returns an estimate of the number of bytes that can be read (or
         * skipped over) from this input stream without blocking by the next
         * caller of a method for this input stream. The next caller might be
         * the same thread or another thread.  A single read or skip of this
         * many bytes will not block, but may read or skip fewer bytes.
         * <p>
         * This method returns the result of {@link #in in}.available().
         *
         * @return     an estimate of the number of bytes that can be read (or skipped
         *             over) from this input stream without blocking.
         * @exception  IOException  if an I/O error occurs.
         */
        public int available() throws IOException {
            return in.available();
        }
    

    描述的很清楚,返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。

    说到这基本就反应过来,再说就有点啰嗦了。

    总结


    像这种问题其实和技术和能力没多大关系、主要是细心和经验。其实定义一个程序员的牛逼与否在于他踩过的坑是否足够多。

    既然说到这那就顺便温故下InputStream的几个方法吧!

    方法摘要

    int available() : 返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。

    void close() : 关闭此输入流并释放与该流关联的所有系统资源。

    void mark(int readlimit): 在此输入流中标记当前的位置。

    boolean markSupported() : 测试此输入流是否支持 mark 和 reset 方法。

    abstract int read() : 测试此输入流是否支持 mark 和 reset 方法。

    int read(byte[] b) : 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。

    int read(byte[] b, int off, int len) : 将输入流中最多 len 个数据字节读入 byte 数组。

    void reset() : 将此流重新定位到最后一次对此输入流调用 mark 方法时的位置。

    long skip(long n) : 跳过和丢弃此输入流中数据的 n 个字节。

    以次简单的问题来对InputStream 温故。

    如有分析的错误的地方、欢迎指正

    相关文章

      网友评论

        本文标题:踩坑笔记 >> InputStream.read(b

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