注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

_

_

 
 
 

日志

 
 

慎用InputStream的read()方法  

2014-11-27 19:38:16|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
慎用InputStream的read()方法
    博客分类:
  • java

JavaSocketOSXMLF#

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代码 复制代码 收藏代码慎用InputStream的read()方法 - redtea - _

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

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 *
 * @author mark
 */
public class MyServerSocket {

    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(8888);
        System.out.println("runing");
        while (true) {
            byte[] b = new byte[22480];
            int readBytes = 0;
            Socket s = ss.accept();
            InputStream is = s.getInputStream();
            while (readBytes < 22480) {
                int read = is.read(b, readBytes, 22480 - readBytes);
                System.out.println(read);
                if (read == -1) {
                    break;
                }
                readBytes += read;
            }
            File f = new File("F:\\project\\bocln_nacec\\xml\\ey.xml");
            if (!f.exists()) {
                f.createNewFile();
                System.out.println("creat " + f.toString());
            }
            FileOutputStream fos = new FileOutputStream(f);
            fos.write(b, 0, readBytes);
            fos.flush();
            fos.close();
            System.out.println("complete");
            is.close();
            s.close();
        }
    }
}

Socket 端:

Java代码 复制代码 收藏代码慎用InputStream的read()方法 - redtea - _

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

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 *
 * @author mark
 */
public class MySocket {

    public static void main(String[] args) throws UnknownHostException, IOException {
        Socket s = new Socket("127.0.0.1", 8888);
        OutputStream os = s.getOutputStream();
        File f = new File("F:\\project\\bocln_nacec\\xml\\ye.xml");
        InputStream is = new FileInputStream(f);
        byte[] b = new byte[22480];
        int i = is.read(b);
        is.close();
        os.write(b, 0, i);
        os.flush();
        os.close();
        s.close();
    }
}

先运行 MyServerSocket ,让后多次运行 MySocket ,这是控制台的输出结果( ye.xml 文件长度为 20389 ):

Java代码 复制代码 收藏代码慎用InputStream的read()方法 - redtea - _

  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?
runing
20389
-1
creat F:\project\bocln_nacec\xml\ey.xml
complete
20389
-1
complete
20389
-1
complete
20389
-1
complete
20389
-1
complete
20389
-1
complete
20389
-1
complete
20389
-1
complete
20389
-1
complete
20389
-1
complete
20389
-1
complete
8760
11629
-1
complete
20389
-1
complete
20389
-1
complete
20389
-1
complete
20389
-1
complete
20389
-1
complete
20389
-1
complete
3760
620
16009
-1
complete
20389
-1
complete
20389
-1
complete
20389
-1
complete
20389
-1
complete
8760
11629
-1
complete
20389
-1
complete
20389
-1
complete
8760
11629
-1
complete
20389
-1
complete
20389
-1
complete
8760
11629
-1
complete
20389
-1
complete
20389
-1
complete
20389
-1
complete
20389
-1
complete
20389
-1
complete
20389
-1
complete
20389
-1
complete
20389
-1
complete
20389
-1
complete
20389
-1
complete
20389
-1
complete
20389
-1
complete
20389
-1
complete
20389
-1
complete

通过观察发现,在大多数情况下,我们能够用 is.read(b, readBytes, 22480 - readBytes) 一次性就读完整个文件,但是还是有极少数情况,我们需要两次(如36、37两行)甚至两次以上(如58、59、60)调用 is.read(b, readBytes, 22480 - readBytes) 方法才能把整个文件读取完。这里由于文件最长只有 20389 ,所以我们能读到的最大字节数也就是 20389 而不会是 22480 了。

那么我们怎样写代码才能保证在数据流没有到达末尾的情况下读取到自己想要的长度的字节数据呢?我们可以这样写:

Java代码 复制代码 收藏代码慎用InputStream的read()方法 - redtea - _

  1. int readBytes=0;?
  2. Byte[] b=new byte[1024]//1024可改成任何需要的值
  3. int len=b.length;?
  4. while (readBytes < len) {?
  5. int read = is.read(b, readBytes, len - readBytes);?
  6. //判断是不是读到了数据流的末尾 ,防止出现死循环。
  7. if (read == -1) {?
  8. break;?
  9. ??????????????? }?
  10. ??????????????? readBytes += read;?
  11. ??????????? }?
  评论这张
 
阅读(156)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017