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

摘要:
InputStream此抽象类是表示字节输入流的所有类的超类。我们从输入流中读取数据最常用的方法基本上就是如下3个read()方法了:1、read()方法,这个方法从输入流中读取数据的下一个字节。

InputStream此抽象类是表示字节输入流的所有类的超类。

我们从输入流中读取数据最常用的方法基本上就是如下3个read()方法了:

1、read()方法,这个方法从输入流中读取数据的下一个字节。返回 0到255范围内的int字节值。如果因为已经到达流末尾而没有可用的字节,则返回值-1。

2、read(byte[]b,intoff,intlen)方法,将输入流中最多 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. packagemyspider;
  2. importjava.io.File;
  3. importjava.io.FileOutputStream;
  4. importjava.io.IOException;
  5. importjava.io.InputStream;
  6. importjava.net.ServerSocket;
  7. importjava.net.Socket;
  8. /**
  9. *
  10. *@authormark
  11. */
  12. publicclassMyServerSocket{
  13. publicstaticvoidmain(String[]args)throwsIOException{
  14. ServerSocketss=newServerSocket(8888);
  15. System.out.println("runing");
  16. while(true){
  17. byte[]b=newbyte[22480];
  18. intreadBytes=0;
  19. Sockets=ss.accept();
  20. InputStreamis=s.getInputStream();
  21. while(readBytes<22480){
  22. intread=is.read(b,readBytes,22480-readBytes);
  23. System.out.println(read);
  24. if(read==-1){
  25. break;
  26. }
  27. readBytes+=read;
  28. }
  29. Filef=newFile("F:\project\bocln_nacec\xml\ey.xml");
  30. if(!f.exists()){
  31. f.createNewFile();
  32. System.out.println("creat"+f.toString());
  33. }
  34. FileOutputStreamfos=newFileOutputStream(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端:

Java代码收藏代码
  1. packagemyspider;
  2. importjava.io.File;
  3. importjava.io.FileInputStream;
  4. importjava.io.IOException;
  5. importjava.io.InputStream;
  6. importjava.io.OutputStream;
  7. importjava.net.Socket;
  8. importjava.net.UnknownHostException;
  9. /**
  10. *
  11. *@authormark
  12. */
  13. publicclassMySocket{
  14. publicstaticvoidmain(String[]args)throwsUnknownHostException,IOException{
  15. Sockets=newSocket("127.0.0.1",8888);
  16. OutputStreamos=s.getOutputStream();
  17. Filef=newFile("F:\project\bocln_nacec\xml\ye.xml");
  18. InputStreamis=newFileInputStream(f);
  19. byte[]b=newbyte[22480];
  20. inti=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):

Java代码收藏代码
  1. runing
  2. 20389
  3. -1
  4. creatF: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. intreadBytes=0;
  2. Byte[]b=newbyte[1024]//1024可改成任何需要的值
  3. intlen=b.length;
  4. while(readBytes<len){
  5. intread=is.read(b,readBytes,len-readBytes);
  6. //判断是不是读到了数据流的末尾,防止出现死循环。
  7. if(read==-1){
  8. break;
  9. }
  10. readBytes+=read;
  11. }

免责声明:文章转载自《[转]慎用InputStream的read()方法》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Django--form保存用户输入内容@ConfigurationProperties 配置详解下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

socket 中read返回0的情况

当client,调用read(socketfd,buffer,n)时,返回0的情况: 1、server端调用了close(soketfd)函数 2、server调用了close(fd,SHUT_WR),关闭server端的写连接,半关闭 关于close 和shutdown的过程 一.void close(fd):close发送的是FIN分节(不一定是发送...

BUUCTF PWN [HarekazeCTF2019]baby_rop2

今天的最后一题 int __cdecl main(int argc, const char **argv, const char **envp) { char buf[28]; // [rsp+0h] [rbp-20h] BYREF int v5; // [rsp+1Ch] [rbp-4h] setvbuf(stdout, 0LL, 2,...

Lua读写文件

文件读写 文件读写对制作游戏很有帮助。可以调用别的文件中的代码,保存最高分、游戏存档、玩家状态等信写到文件中。 首先,让我们看一个简单的命令:dofile。这个命令会读入另一个文件的代码并立即执行。 代码: dofile("./test.lua") 很简单的命令。注意 ./ 是指根目录,不是子目录。如果是子目录,应该这样用: 代码: dofi...

WPF 进度条

前台新建一个控件ProgressBar控件,并命名为pbDown            WebRequest request = WebRequest.Create("http://files.cnblogs.com/fornet/404.rar");            WebResponse respone = request.GetResponse...

Linux网络编程 select/epoll得知socket有数据可读,如何判断数据全部被读取完毕?

补充一点:只有在使用epoll ET(Edge Trigger)模式的时候,才需要关注数据是否读取完毕了。使用select或者epoll的LT模式,其实根本不用关注数据是否读完了,select/epoll检测到有数据可读去读就OK了。 这里有两种做法: 1. 针对TCP,调用recv方法,根据recv方法的返回值,如果返回值小于我们指定的recv buf...

GitHub 实现多人协同提交代码并且权限分组管理

前言: 在上一篇文章中Android github 快速实现多人协作(http://www.cnblogs.com/zhaoyanjun/p/5829142.html)介绍了如何快速的实现多人协作的功能。 其优点是:操作简单,快速上手。缺点是:没有办法实现权限控制。为啥要权限控制?这是一个蛋疼的问题,因为我们为了项目的安全考虑,需要对一部分人开放只读权限(...