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 端:

  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. }

Socket 端:

  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. }

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

  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 了。

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

  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. }
 

[转]慎用InputStream的read()方法的更多相关文章

  1. 为什么阿里Java手册推荐慎用 Object 的 clone 方法来拷贝对象

    图片若无法显示,可至掘金查看https://juejin.im/post/5d425230f265da039519d248 前言 在阿里Java开发手册中,有这么一条建议:慎用 Object 的 cl ...

  2. 获取InputStream对象的方法

    获取InputStream对象的方法 getResourceAsStream(String path) 默认path路径位于Class所在Module的src目录下 . InputStream is ...

  3. Java:浅谈InputStream的close方法

    原则:最好在任何时候使用InputStream或者OutputStream的时候,在finally中调用close()方法,显式关闭. 一个典型的示例 InputStream in = null; t ...

  4. 【Java基础01】Java InputStream的read方法

    JDK关于InputStream中的read方法的描述: (1) read() :  从输入流中读取数据的下一个字节,返回0到255范围内的int字节值.如果因为已经到达流末尾而没有可用的字节,则返回 ...

  5. [五] JavaIO之InputStream OutputStream简介 方法列表说明

      InputStream 和 OutputStream 对于字节流的输入和输出 是作为协议的存在 所以有必要了解下这两个类提供出来的基本约定 这两个类是抽象类,而且基本上没什么实现,都是依赖于子类具 ...

  6. JAVA IO流 InputStream流 Read方法

    read()首先我们来看这个没有参数的read方法,从(来源)输入流中(读取的内容)读取数据的下一个字节到(去处)java程序内部中,返回值为0到255的int类型的值,返回值为字符的ACSII值(如 ...

  7. 慎用ArrayList的contains方法,使用HashSet的contains方法代替

    在启动一个应用的时候,发现其中有一处数据加载要数分钟,刚开始以为是需要load的数据比较多的缘故,查了一下数据库有6条左右,但是单独写了一个数据读取的方法,将这6万多条全部读过来,却只需要不到10秒钟 ...

  8. 踩过的坑系列之InputStream.read(byte[])方法

    项目之前都是好好的,最近现场那边出现一个问题,报错不是合法的json字符串,这个json字符串是通过http请求访问获得的. 通过直接在浏览器上直接访问http这个请求,发现返回的json也是完全正确 ...

  9. InputStream中mark方法使用

    在调用mark的地方做上标记,参数readlimit说明在读取readlimit个字符后书签做废(6.0好像没有失效 ,仍然可以标记位置),使用reset后回到标记的位置.import java.io ...

随机推荐

  1. webservice 尝试加载 Oracle 客户端库时引发 BadImageFormatException。如果在安装 32 位 Oracle 客户端组件的情况下运行,将出现此问题

    最近做的项目中,应用服务器迁移到另外一台服务器,操作系统升级为win10,配置好IIS里的应用程序发布网站和Webservice网站后, 客户端程序调用Webservice出错: “尝试加载 Orac ...

  2. js对象,类

    js闭包网站:http://www.cnblogs.com/qieguo/p/5457040.html 有权访问另一个函数作用域内变量的函数都是闭包. 这里 inc 函数访问了构造函数 a 里面的变量 ...

  3. C++侵入式链表

    C++标准模板库中的list是非侵入式的链表,当我们通过对象来删除容器中的对象时,需要从头到尾查找一次得到iterator,最后通过iterator来删除对象.这样删除容器中的对象时比较缓慢,所以就实 ...

  4. 【第三篇】学习 android 事件总线androidEventbus之发布事件,子线程中接收

    发送和接收消息的方式类似其他的发送和接收消息的事件总线一样,不同的点或者应该注意的地方: 1,比如在子线程构造方法里面进行实现总线的注册操作: 2,要想子线程中接收消息的功能执行,必须启动线程. 3, ...

  5. NEU OJ 1651 Great number

    循环节是2000000016 字符串读入,用一下高精度对2000000016取个模,用一下快速幂就可以算出答案了. #include <cstdio> #include <iostr ...

  6. Dell7040mt安装win7系统说明

    几天新买的Dell7040mt收到了,机器预装了win10系统,把win10作为开发平台,可能会有一些问题,所以改为win7,今天折腾了一天,终于把win7系统装上了.总结一下安装的步骤. 1 准备启 ...

  7. VMware+Windbg双机调试

    虚拟机使用XP系统:

  8. C++ primer 练习 12.7

    重做上一题,这次使用shared_ptr 而不是内置指针.上一题题目为:(编写函数,返回一个动态分配的int的vector.将此vector传递给另一个函数,这个函数读取标准输入,将读入的值保存在ve ...

  9. elasticsearch简介

    elasticsearch 摘要: 1 es是一个分布式全文搜索引擎.特定是:无中心化,实时,扩展性强. 2. es有几个好的概念或者特点:(1)cluster 集群无中心化.(2)shards.分片 ...

  10. 轻松创建nodejs服务器(1):一个简单nodejs服务器例子

    这篇文章主要介绍了一个简单nodejs服务器例子,本文实现了一个简单的hello world例子,并展示如何运行这个服务器,需要的朋友可以参考下   我们先来实现一个简单的例子,hello world ...