• [转]慎用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.             }  
     
  • 相关阅读:
    pbfunc外部函数扩展应用-直接在Datawindow中生成QR二维码,非图片方式
    一、PBNI环境搭建及初步使用
    Powerbuilder编写身份证校验码
    Maven本地安装JAR包组件
    使用SSH通过秘钥登录Linux
    Intellij IDEA下载
    ubuntu使用root用户登录桌面
    Ubuntu安装JDK1.8与配置环境变量
    Ubuntu 安装 JDK 7 / JDK8 的两种方式
    CentOS 7.0关闭默认防火墙启用iptables防火墙
  • 原文地址:https://www.cnblogs.com/xunbu7/p/5020265.html
Copyright © 2020-2023  润新知