1. 程式人生 > 其它 >踩過的坑系列之InputStream.read(byte[])方法

踩過的坑系列之InputStream.read(byte[])方法

  專案之前都是好好的,最近現場那邊出現一個問題,報錯不是合法的json字串,這個json字串是通過http請求訪問獲得的。

  通過直接在瀏覽器上直接訪問http這個請求,發現返回的json也是完全正確的。後來排查程式碼才發現了原來錯誤出在從位元組流中讀取資料這裡:

  看下之前出錯程式碼:這個方法是處理InputStream,然後返回成一個字串。

 1 public String process(InputStream in, String charset) {
 2      byte[] buf = new byte[1024];
 3      StringBuffer sb = new StringBuffer();
 4      try {
 5          while (in.read(buf) != -1) {
 6              sb.append(new String(buf, charset));
 7          }
 8     } catch (IOException e) {
 9          e.printStackTrace();
10     }
11      return sb.toString();
12 }

   有問題的程式碼在第6行,發現之前專案沒出錯的原因是InputStream裡面的資料少,還不夠1024個位元組,while那裡迴圈一次就好了,得到一個正確格式的json串;後面出錯了是因為InputStream裡面資料比較多,while需要2次了,第一次讀取之後buf裡面滿了,第二次讀取發現read(byte[])方法不會去清空緩衝區陣列,第二次實際上read位元組只有100個,buf裡面只替換前100個位元組內容,然後通過第6行程式碼append到字串裡了,就造成了最後獲得的字串不是json格式,造成之後json解析出錯。

  知道問題後,將之前程式碼改為下,既然每次不會去清空緩衝區陣列內容,那就通過讀取長度來append字串,問題解決:

 1 public String process(InputStream in, String charset) {
 2     byte[] buf = new byte[1024];
 3     StringBuffer sb = new StringBuffer();
 4     int len = 0;
 5     try {
 6         while ((len=in.read(buf)) != -1) {
 7             sb.append(new String(buf, 0, len, charset));
 8         }
 9     } catch (IOException e) {
10         e.printStackTrace();
11     }
12     return sb.toString();
13 }

 

    後來查了下JDK API,發現API上也說明過了,只是以前沒注意,關鍵在於加黑字型,不影響b[k]到b[b.length-1]的元素:

  附上API:

    public int read(byte[] b) throws IOException    
  從輸入流中讀取一定數量的位元組,並將其儲存在緩衝區陣列 b 中。以整數形式返回實際讀取的位元組數。
  在輸入資料可用、檢測到檔案末尾或者丟擲異常前,此方法一直阻塞。
  如果 b 的長度為 0,則不讀取任何位元組並返回 0;否則,嘗試讀取至少一個位元組。如果因為流位於檔案末尾而沒有可用的位元組,則返回值 -1;否則,至少讀取一個位元組並將其儲存在 b 中。將讀取的第一個位元組儲存在元素 b[0] 中,下一個儲存在 b[1] 中,依次類推。讀取的位元組數最多等於 b 的長度。設 k 為實際讀取的位元組數;這些位元組將儲存在 b[0]b[k-1] 的元素中,不影響 b[k]b[b.length-1] 的元素。