BufferedReader的readLine()方法是阻塞式的, 如果到達流末尾, 就返回null, 但如果client的socket末經關閉就銷毀, 則會產生IO異常. 正常的方法就是使用socket.close()關閉不需要的socket.
雖然寫IO方面的程序不多,但BufferedReader/BufferedInputStream倒是用過好幾次的,原因是:
它有一個很特別的方法:readLine(),使用起來特別方便,每次讀回來的都是一行,省了很多手動拼接buffer的瑣碎;
它比較高效,相對於一個字符/字節地讀取、轉換、返回來說,它有一個緩沖區,讀滿緩沖區才返回;一般情況下,都建議使用它們把其它Reader/InputStream包起來,使得讀取數據更高效。
對於文件來說,經常遇到一行一行的,特別相符情景。
這次是在藍牙開發時,使用兩個藍牙互相傳數據(即一個發一個收),bluecove這個開源組件已經把數據讀取都封裝成InputStream了,也就相當於平時的IO讀取了,很自然就使用起readLine()來了。
發數據:
BufferedWriter output = new BufferedWriter(new OutputStreamWriter(conn.openOutputStream())); int i = 1; String message = "message " + i; while(isRunning) { output.write(message+"/n"); i++; }
讀數據:
BufferedReader input = new BufferedReader(new InputStreamReader(m_conn.openInputStream())); String message = ""; String line = null; while((line = m_input.readLine()) != null) { message += line; } System.out.println(message);
上面是代碼的節選,使用這段代碼會發現寫數據時每次都成功,而讀數據側卻一直沒有數據輸出(除非把流關掉)。經過折騰,原來這里面有幾個大問題需要理解:
- 誤以為readLine()是讀取到沒有數據時就返回null(因為其它read方法當讀到沒有數據時返回-1),而實際上readLine()是一個阻塞函數,當沒有數據讀取時,就一直會阻塞在那,而不是返回null;因為readLine()阻塞后,System.out.println(message)這句根本就不會執行到,所以在接收端就不會有東西輸出。要想執行到System.out.println(message),一個辦法是發送完數據后就關掉流,這樣readLine()結束阻塞狀態,而能夠得到正確的結果,但顯然不能傳一行就關一次數據流;另外一個辦法是把System.out.println(message)放到while循環體內就可以。
- readLine()只有在數據流發生異常或者另一端被close()掉時,才會返回null值。
- 如果不指定buffer大小,則readLine()使用的buffer有8192個字符。在達到buffer大小之前,只有遇到"/r"、"/n"、"/r/n"才會返回。
小結,使用readLine()一定要注意:
- 讀入的數據要注意有/r或/n或/r/n
- 沒有數據時會阻塞,在數據流異常或斷開時才會返回null
- 使用socket之類的數據流時,要避免使用readLine(),以免為了等待一個換行/回車符而一直阻塞
正確讀取Socket InputStream 的方法
package com.photoManage.utils; import java.io.*; public class StreamTool { public static void main(String[] args) { try { File file = new File("C:\\demo.log"); FileInputStream fin = new FileInputStream(file); byte[] filebt = readStream(fin); System.out.println(filebt.length); } catch (Exception e) { e.printStackTrace(); } } /** * @功能 讀取流 * @param inStream * @return 字節數組 * @throws Exception */ public static byte[] readStream(InputStream inStream) throws Exception { int count = 0; while (count == 0) { count = inStream.available(); } byte[] b = new byte[count]; inStream.read(b); return b; } }
參考博客:
http://cuisuqiang.iteye.com/blog/1434416#comments