资讯专栏INFORMATION COLUMN

踩坑历程 >> InputStream.read(byte[] b) 造成死循环

he_xd / 2798人阅读

摘要:关闭此输入流并释放与该流关联的所有系统资源。在此输入流中标记当前的位置。从输入流中读取一定数量的字节,并将其存储在缓冲区数组中。将此流重新定位到最后一次对此输入流调用方法时的位置。

一、写在前面

在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 len bytes of data from this input stream
     * into an array of bytes. If len is not zero, the method
     * blocks until some input is available; otherwise, no
     * bytes are read and 0 is returned.
     * 

* This method simply performs in.read(b, off, len) * and returns the result. * * @param b the buffer into which the data is read. * @param off the start offset in the destination array b * @param len the maximum number of bytes read. * @return the total number of bytes read into the buffer, or * -1 if there is no more data because the end of * the stream has been reached. * @exception NullPointerException If b is null. * @exception IndexOutOfBoundsException If off is negative, * len is negative, or len is greater than * b.length - off * @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.
     * 

* 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 温故。

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/74640.html

相关文章

  • 重拾Java Network Programming(一)IO流

    摘要:不同类型的流入,往往对应于不同类型的流数据。所以通常会将字节缓存到一定数量后再发送。如果是,则将两个标记都抛弃并且将之前的内容作为一行返回。因此二者陷入死锁。因此推出了和类。 前言 最近在重拾Java网络编程,想要了解一些JAVA语言基本的实现,这里记录一下学习的过程。 阅读之前,你需要知道 网络节点(node):位于网络上的互相连通的设备,通常为计算机,也可以是打印机,网桥,路由器等...

    Lycheeee 评论0 收藏0
  • Java IO学习五

    摘要:不建议对这两个对象尝试使用单个线程,因为这样可能会造成该线程死锁。构造函数创建尚未连接到管道输入流的管道输出流。通常,数据由某个线程从对象读取,并由其他线程将其写入到相应的。 管道流 管道流的主要作用是可以进行两个线程间的通讯,分为管道输出流(PipedOutputStream)、管道输入流(PipedInputStream),如果想要进行管道输出,则必须要把输出流连在输入流之上,在...

    gaomysion 评论0 收藏0
  • Python流程控制if条件选择与for循环

      小编写这篇文章的主要目的,是用来给大家做一个介绍的,介绍关于在Python中。流程控制条件一些问题,另外还有如何进行for循环呢?下面小编给大家详细的进行阐述一下。1、if条件选择   #coding:utf-8   num=23   ifnum>2:   print("dayu")   ifnum<2:   print("xiaoyu") ...

    89542767 评论0 收藏0
  • 关于java用字节流和字符流读取文件的各种情况

    摘要:遇到的问题在用通信传输一个文件以及其他的非文件的时候总是传到服务端的文件出错,后来发现是在用字符流和字节流在读取各种文件上的差别所导致的读取文件的方式字节流读取和,其读取的方式按字节读取,这个常用于读取原始数据。 遇到的问题 在用socket通信传输一个pdf文件以及其他的非txt文件的时候总是传到服务端的文件出错,后来发现是在用字符流和字节流在读取各种文件上的差别所导致的 java读...

    tommego 评论0 收藏0
  • 怎么使用python控制if语句和for循环

      小编写这篇文章的主要目的,主要是给大家做一个比较详细的解答,因为很多人在使用python的时候,往往会遇到各种各样的问题,比如if控制语句和for循环这些内容,不能够合理地进行运用,那么,具体要怎么使用呢?下面小编就给大家详细解答下。  1、if条件选择 #coding:utf-8   num=23   ifnum&gt;2:   print("dayu")   i...

    89542767 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<