踩坑筆記 >> InputStream.read(byte[]) 造成死循環

寫在前面


在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 溫故。

如有分析的錯誤的地方、歡迎指正
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章