[转]慎用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:projectocln_nacecxmley.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.             }  
 
原文地址:https://www.cnblogs.com/xunbu7/p/5020265.html