天天看點

java InputStream讀取資料問題

byte[] b),read(byte[] b, int off, int len)。其中read()方法是一次讀取一個位元組,鬼都知道效率是非常低的。是以最好是使用後面兩個方法。

例如以下代碼:

  1. /**
  2.  * 讀取流
  3.  * 
  4.  * @param inStream
  5.  * @return 位元組數組
  6.  * @throws Exception
  7.  */
  8. public static byte[] readStream(InputStream inStream) throws
  9. new
  10. byte[] buffer = new byte[1024];  
  11. int len = -1;  
  12. while ((len = inStream.read(buffer)) != -1) {  
  13. 0, len);  
  14.     }  
  15.     outSteam.close();  
  16.     inStream.close();  
  17. return
  18. }  

我們來測試一下:

  1. public static void
  2. try
  3. new File("C:\\ceshi.txt");  
  4. new
  5. byte[] filebt = readStream(fin);  
  6.         System.out.println(filebt.length);  
  7. catch
  8.         e.printStackTrace();  
  9.     }     
  10. }  

背景會列印這個文本的位元組大小。看起來,這個是沒有問題的。

關于InputStream類的available()方法

這個方法的意思是傳回此輸入流下一個方法調用可以不受阻塞地從此輸入流讀取(或跳過)的估計位元組數。為什麼需要這個方法?因為在一些網絡應用中,資料流并不是一次性就能傳遞的,如果我們還是像上面那樣去将這個流轉換,會出問題的。我們來做一個例子,這是一個Socket程式設計的簡單例子,具體Socket内容我會在後面文章中解釋的。

首先編寫兩個類,一個使用者初始化Socket服務,并且處理每個請求都有新的線程去處理,代碼如下:

  1. package
  2. import
  3. public class
  4. public static void
  5. try
  6. // 啟動監聽端口 8001
  7. new ServerSocket(8001);  
  8. boolean bRunning = true;  
  9. while
  10. // 接收請求
  11.                 Socket s = ss.accept();  
  12. // 将請求指定一個線程去執行
  13. new Thread(new
  14.             }  
  15. catch
  16.             e.printStackTrace();  
  17.         }  
  18.     }  
  19. }  

那麼處理類我們也來看一下:

  1. package
  2. import
  3. import
  4. import
  5. public class DstServiceImpl implements
  6. null;  
  7. public
  8. this.socket = s;  
  9.     }  
  10. public void
  11. try
  12.             InputStream ips = socket.getInputStream();  
  13.             OutputStream ops = socket.getOutputStream();  
  14. while (true) {  
  15. byte[] bt = StreamTool.readStream(ips);  
  16. new
  17. "主機收到資訊:"
  18. "你好,主機已經收到資訊!";  
  19.                 ops.write(restr.getBytes());  
  20.                 ops.flush();  
  21.             }  
  22. catch
  23.             e.printStackTrace();  
  24.         }  
  25.     }  
  26. }  

 至于工具類,我就直接給代碼了:

  1. package
  2. import
  3. public class
  4. public static void
  5. try
  6. new File("C:\\ceshi.txt");  
  7. new
  8. byte[] filebt = readStream(fin);  
  9.             System.out.println(filebt.length);  
  10. catch
  11.             e.printStackTrace();  
  12.         }     
  13.     }     
  14. /**
  15.      * @功能 讀取流
  16.      * @param inStream
  17.      * @return 位元組數組
  18.      * @throws Exception
  19.      */
  20. public static byte[] readStream(InputStream inStream) throws
  21. new
  22. byte[] buffer = new byte[1024];  
  23. int len = -1;  
  24. while ((len = inStream.read(buffer)) != -1) {  
  25. 0, len);  
  26.         }  
  27.         outSteam.close();  
  28.         inStream.close();  
  29. return
  30.     }  
  31. }  

 你可以直接運作這個類,會看到流被轉換的效果。

我們來寫一個Socket用戶端測試一下:

  1. package
  2. import
  3. import
  4. import
  5. public class
  6. public static void
  7. try
  8. new Socket("127.0.0.1", 8001);  
  9. // 開啟保持活動狀态的套接字
  10. true);  
  11. // 設定讀取逾時時間
  12. 30 * 1000);  
  13.             OutputStream ops = socket.getOutputStream();  
  14. "你好,我是崔素強!";  
  15.             ops.write(mess.getBytes());  
  16.             InputStream ips = socket.getInputStream();  
  17. byte[] rebyte = StreamTool.readStream(ips);  
  18. new
  19. "收到主機消息:"
  20.             socket.close();  
  21. catch
  22.             e.printStackTrace();  
  23.         }  
  24.     }  
  25. }  

 先運作DstService,然後運作用戶端,看效果。會發現,控制台沒有任何輸出。經過調試發現,因為請求死在了

  1. while ((len = inStream.read(buffer)) != -1) {  

這行代碼上面。這就是在網絡應用中會造成的後果。那麼如何解決呢?有的人給出了如下代碼:

  1. int
  2. byte[] b = new byte[count];  
  3. in.read(b);  

可是在進行網絡操作時往往出錯,因為你調用available()方法時,對發發送的資料可能還沒有到達,你得到的count是0。需要做如下修改,是我們的讀取流方法改成如下:

  1. /**
  2.  * @功能 讀取流
  3.  * @param inStream
  4.  * @return 位元組數組
  5.  * @throws Exception
  6.  */
  7. public static byte[] readStream(InputStream inStream) throws
  8. int count = 0;  
  9. while (count == 0) {  
  10.         count = inStream.available();  
  11.     }  
  12. byte[] b = new byte[count];  
  13.     inStream.read(b);  
  14. return
  15. }  

下面你在運作,會看到服務端和用戶端都收到了消息。 

關于InputStream.read(byte[] b)和InputStream.read(byte[] b,int off,int len)這兩個方法都是用來從流裡讀取多個位元組的,有經驗的程式員就會發現,這兩個方法經常 讀取不到自己想要讀取的個數的位元組。比如第一個方法,程式員往往希望程式能讀取到b.length個位元組,而實際情況是,系統往往讀取不了這麼多。仔細閱讀Java的API說明就發現了,這個方法 并不保證能讀取這麼多個位元組,它隻能保證最多讀取這麼多個位元組(最少1個)。是以,如果要讓程式讀取count個位元組,最好用以下代碼:

  1. int count = 100;  
  2. byte[] b = new byte[count];  
  3. int readCount = 0; // 已經成功讀取的位元組的個數
  4. while
  5.     readCount += inStream.read(b, readCount, count - readCount);  
  6. }