1. 程式人生 > >關於BufferedReader的read()及readLine()

關於BufferedReader的read()及readLine()

 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()一定要注意:

  1. 讀入的資料要注意有/r或/n或/r/n
  2. 沒有資料時會阻塞,在資料流異常或斷開時才會返回null
  3. 使用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; 
    }  
}  

(轉自 程式人生0407