[轉]慎用InputStream的read()方法


InputStream 此抽象類是表示字節輸入流的所有類的超類。

          我們從輸入流中讀取數據最常用的方法基本上就是如下 3 個 read() 方法了:

         1 、 read () 方法,這個方法 從輸入流中讀取數據的下一個字節。返回 0 到 255 范圍內的 int 字節值。如果因為已經到達流末尾而沒有可用的字節,則返回值 -1 。

         2 、 read (byte[] b,int off,int len) 方法, 將輸入流中最多 len 個數據字節讀入 byte 數組。嘗試讀取 len 個字節,但讀取的字節也可能小於該值。以整數形式返回實際讀取的字節數。

         3 、 read (byte[] b) 方法, 從輸入流中讀取一定數量的字節,並將其存儲在緩沖區數組 b 中。以整數形式返回實際讀取的字節數。

         第一個方法典型的確定就是處理效率低,不是某些特殊情況,很少使用它,下面說說第 2 個方法跟第 3 個方法,第 3 個方法的本本質其實就是第 2 個方法的特殊情況, 效果等同於:

          read(b, 0, b.length)

所以這里把他們放着一起討論。

         從第 2 個方法的 API 文檔說明來看:“ 將輸入流中最多 len 個數據字節讀入 byte 數組。嘗試讀取 len 個字節,但讀取的字節也可能小於該值。以整數形式返回實際讀取的字節數。”,最多讀取 len 個字節,這究竟是何意? API 文檔並沒有詳細說明。是不是就意味着有可能(注意這里是有可能而不是一定,)讀取不到 len 個字節呢?答案是“是的”。雖然造成這種情況的原因是什么個人並不知道,但是我們可以通過例子來發現這種情況,下面是源代碼(由於只是簡單的示例,所以代碼也就隨便寫了):

 

ServerSocket 端:

 

Java代碼   收藏代碼
  1. package myspider;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileOutputStream;  
  5. import java.io.IOException;  
  6. import java.io.InputStream;  
  7. import java.net.ServerSocket;  
  8. import java.net.Socket;  
  9.   
  10. /** 
  11.  * 
  12.  * @author mark 
  13.  */  
  14. public class MyServerSocket {  
  15.   
  16.     public static void main(String[] args) throws IOException {  
  17.         ServerSocket ss = new ServerSocket(8888);  
  18.         System.out.println("runing");  
  19.         while (true) {  
  20.             byte[] b = new byte[22480];  
  21.             int readBytes = 0;  
  22.             Socket s = ss.accept();  
  23.             InputStream is = s.getInputStream();  
  24.             while (readBytes < 22480) {  
  25.                 int read = is.read(b, readBytes, 22480 - readBytes);  
  26.                 System.out.println(read);  
  27.                 if (read == -1) {  
  28.                     break;  
  29.                 }  
  30.                 readBytes += read;  
  31.             }  
  32.             File f = new File("F:\\project\\bocln_nacec\\xml\\ey.xml");  
  33.             if (!f.exists()) {  
  34.                 f.createNewFile();  
  35.                 System.out.println("creat " + f.toString());  
  36.             }  
  37.             FileOutputStream fos = new FileOutputStream(f);  
  38.             fos.write(b, 0, readBytes);  
  39.             fos.flush();  
  40.             fos.close();  
  41.             System.out.println("complete");  
  42.             is.close();  
  43.             s.close();  
  44.         }  
  45.     }  
  46. }  

 

Socket 端:

 

Java代碼   收藏代碼
  1. package myspider;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileInputStream;  
  5. import java.io.IOException;  
  6. import java.io.InputStream;  
  7. import java.io.OutputStream;  
  8. import java.net.Socket;  
  9. import java.net.UnknownHostException;  
  10.   
  11. /** 
  12.  * 
  13.  * @author mark 
  14.  */  
  15. public class MySocket {  
  16.   
  17.     public static void main(String[] args) throws UnknownHostException, IOException {  
  18.         Socket s = new Socket("127.0.0.1", 8888);  
  19.         OutputStream os = s.getOutputStream();  
  20.         File f = new File("F:\\project\\bocln_nacec\\xml\\ye.xml");  
  21.         InputStream is = new FileInputStream(f);  
  22.         byte[] b = new byte[22480];  
  23.         int i = is.read(b);  
  24.         is.close();  
  25.         os.write(b, 0, i);  
  26.         os.flush();  
  27.         os.close();  
  28.         s.close();  
  29.     }  
  30. }  

 

 

先運行 MyServerSocket ,讓后多次運行 MySocket ,這是控制台的輸出結果( ye.xml 文件長度為 20389 ):

 

Java代碼   收藏代碼
  1. runing  
  2. 20389  
  3. -1  
  4. creat F:\project\bocln_nacec\xml\ey.xml  
  5. complete  
  6. 20389  
  7. -1  
  8. complete  
  9. 20389  
  10. -1  
  11. complete  
  12. 20389  
  13. -1  
  14. complete  
  15. 20389  
  16. -1  
  17. complete  
  18. 20389  
  19. -1  
  20. complete  
  21. 20389  
  22. -1  
  23. complete  
  24. 20389  
  25. -1  
  26. complete  
  27. 20389  
  28. -1  
  29. complete  
  30. 20389  
  31. -1  
  32. complete  
  33. 20389  
  34. -1  
  35. complete  
  36. 8760  
  37. 11629  
  38. -1  
  39. complete  
  40. 20389  
  41. -1  
  42. complete  
  43. 20389  
  44. -1  
  45. complete  
  46. 20389  
  47. -1  
  48. complete  
  49. 20389  
  50. -1  
  51. complete  
  52. 20389  
  53. -1  
  54. complete  
  55. 20389  
  56. -1  
  57. complete  
  58. 3760  
  59. 620  
  60. 16009  
  61. -1  
  62. complete  
  63. 20389  
  64. -1  
  65. complete  
  66. 20389  
  67. -1  
  68. complete  
  69. 20389  
  70. -1  
  71. complete  
  72. 20389  
  73. -1  
  74. complete  
  75. 8760  
  76. 11629  
  77. -1  
  78. complete  
  79. 20389  
  80. -1  
  81. complete  
  82. 20389  
  83. -1  
  84. complete  
  85. 8760  
  86. 11629  
  87. -1  
  88. complete  
  89. 20389  
  90. -1  
  91. complete  
  92. 20389  
  93. -1  
  94. complete  
  95. 8760  
  96. 11629  
  97. -1  
  98. complete  
  99. 20389  
  100. -1  
  101. complete  
  102. 20389  
  103. -1  
  104. complete  
  105. 20389  
  106. -1  
  107. complete  
  108. 20389  
  109. -1  
  110. complete  
  111. 20389  
  112. -1  
  113. complete  
  114. 20389  
  115. -1  
  116. complete  
  117. 20389  
  118. -1  
  119. complete  
  120. 20389  
  121. -1  
  122. complete  
  123. 20389  
  124. -1  
  125. complete  
  126. 20389  
  127. -1  
  128. complete  
  129. 20389  
  130. -1  
  131. complete  
  132. 20389  
  133. -1  
  134. complete  
  135. 20389  
  136. -1  
  137. complete  
  138. 20389  
  139. -1  
  140. complete  

 

 

         通過觀察發現,在大多數情況下,我們能夠用 is.read(b, readBytes, 22480 - readBytes) 一次性就讀完整個文件,但是還是有極少數情況,我們需要兩次(如36、37兩行)甚至兩次以上(如58、59、60)調用 is.read(b, readBytes, 22480 - readBytes) 方法才能把整個文件讀取完。這里由於文件最長只有 20389 ,所以我們能讀到的最大字節數也就是 20389 而不會是 22480 了。

         那么我們怎樣寫代碼才能保證在數據流沒有到達末尾的情況下讀取到自己想要的長度的字節數據呢?我們可以這樣寫:   

 

Java代碼   收藏代碼
  1. int readBytes=0;  
  2.   
  3. Byte[] b=new byte[1024]//1024可改成任何需要的值  
  4.   
  5. int len=b.length;  
  6.   
  7. while (readBytes < len) {  
  8.   
  9.                 int read = is.read(b, readBytes, len - readBytes);  
  10.   
  11.                //判斷是不是讀到了數據流的末尾 ,防止出現死循環。  
  12.   
  13.                 if (read == -1) {  
  14.   
  15.                     break;  
  16.   
  17.                 }  
  18.   
  19.                 readBytes += read;  
  20.   
  21.             }  
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM