寫在前面
在Java中流的一系列操作对湃,可能會感到既熟悉又陌生询吴。熟悉是因為很基礎且出鏡率很高杯矩,陌生對大多數程序員平時工作中很少寫相關的代碼。
~~ 我是很少寫~~
回歸正題巾表,本章我不不是探討流汁掠,主要來說下造成‘標題’問題的原因。
問題很簡單集币,稍微看下源碼或者debug下就可以找到問題所在考阱,這是一些細節(jié)問題,既然出現了在此做下記錄鞠苟,給自己一個警惕乞榨。
場景引入
今天微信上突然收到前同事一段這樣的問題描述
在讀取文件時如果文件為空、導致進入while死循環(huán)当娱,
并附上一段代碼吃既。
/**
* 將文件數據流寫入到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死循環(huán)的條件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();
}
描述的很清楚媒楼,返回此輸入流下一個方法調用可以不受阻塞地從此輸入流讀壤肿稹(或跳過)的估計字節(jié)數。
說到這基本就反應過來匣砖,再說就有點啰嗦了科吭。
總結
像這種問題其實和技術和能力沒多大關系、主要是細心和經驗猴鲫。其實定義一個程序員的牛逼與否在于他踩過的坑是否足夠多。
既然說到這那就順便溫故下InputStream的幾個方法吧谣殊!
方法摘要
int available() : 返回此輸入流下一個方法調用可以不受阻塞地從此輸入流讀确鞴病(或跳過)的估計字節(jié)數。
void close() : 關閉此輸入流并釋放與該流關聯的所有系統(tǒng)資源姻几。
void mark(int readlimit): 在此輸入流中標記當前的位置宜狐。
boolean markSupported() : 測試此輸入流是否支持 mark 和 reset 方法。
abstract int read() : 測試此輸入流是否支持 mark 和 reset 方法蛇捌。
int read(byte[] b) : 從輸入流中讀取一定數量的字節(jié)抚恒,并將其存儲在緩沖區(qū)數組 b 中。
int read(byte[] b, int off, int len) : 將輸入流中最多 len 個數據字節(jié)讀入 byte 數組络拌。
void reset() : 將此流重新定位到最后一次對此輸入流調用 mark 方法時的位置俭驮。
long skip(long n) : 跳過和丟棄此輸入流中數據的 n 個字節(jié)。
以次簡單的問題來對InputStream 溫故春贸。
如有分析的錯誤的地方混萝、歡迎指正