天天看点

java InputStream读取数据问题

byte[] b),read(byte[] b, int off, int len)。其中read()方法是一次读取一个字节,鬼都知道效率是非常低的。所以最好是使用后面两个方法。

例如以下代码:

  1. /**
  2.  * 读取流
  3.  * 
  4.  * @param inStream
  5.  * @return 字节数组
  6.  * @throws Exception
  7.  */
  8. public static byte[] readStream(InputStream inStream) throws
  9. new
  10. byte[] buffer = new byte[1024];  
  11. int len = -1;  
  12. while ((len = inStream.read(buffer)) != -1) {  
  13. 0, len);  
  14.     }  
  15.     outSteam.close();  
  16.     inStream.close();  
  17. return
  18. }  

我们来测试一下:

  1. public static void
  2. try
  3. new File("C:\\ceshi.txt");  
  4. new
  5. byte[] filebt = readStream(fin);  
  6.         System.out.println(filebt.length);  
  7. catch
  8.         e.printStackTrace();  
  9.     }     
  10. }  

后台会打印这个文本的字节大小。看起来,这个是没有问题的。

关于InputStream类的available()方法

这个方法的意思是返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。为什么需要这个方法?因为在一些网络应用中,数据流并不是一次性就能传递的,如果我们还是像上面那样去将这个流转换,会出问题的。我们来做一个例子,这是一个Socket编程的简单例子,具体Socket内容我会在后面文章中解释的。

首先编写两个类,一个用户初始化Socket服务,并且处理每个请求都有新的线程去处理,代码如下:

  1. package
  2. import
  3. public class
  4. public static void
  5. try
  6. // 启动监听端口 8001
  7. new ServerSocket(8001);  
  8. boolean bRunning = true;  
  9. while
  10. // 接收请求
  11.                 Socket s = ss.accept();  
  12. // 将请求指定一个线程去执行
  13. new Thread(new
  14.             }  
  15. catch
  16.             e.printStackTrace();  
  17.         }  
  18.     }  
  19. }  

那么处理类我们也来看一下:

  1. package
  2. import
  3. import
  4. import
  5. public class DstServiceImpl implements
  6. null;  
  7. public
  8. this.socket = s;  
  9.     }  
  10. public void
  11. try
  12.             InputStream ips = socket.getInputStream();  
  13.             OutputStream ops = socket.getOutputStream();  
  14. while (true) {  
  15. byte[] bt = StreamTool.readStream(ips);  
  16. new
  17. "主机收到信息:"
  18. "你好,主机已经收到信息!";  
  19.                 ops.write(restr.getBytes());  
  20.                 ops.flush();  
  21.             }  
  22. catch
  23.             e.printStackTrace();  
  24.         }  
  25.     }  
  26. }  

 至于工具类,我就直接给代码了:

  1. package
  2. import
  3. public class
  4. public static void
  5. try
  6. new File("C:\\ceshi.txt");  
  7. new
  8. byte[] filebt = readStream(fin);  
  9.             System.out.println(filebt.length);  
  10. catch
  11.             e.printStackTrace();  
  12.         }     
  13.     }     
  14. /**
  15.      * @功能 读取流
  16.      * @param inStream
  17.      * @return 字节数组
  18.      * @throws Exception
  19.      */
  20. public static byte[] readStream(InputStream inStream) throws
  21. new
  22. byte[] buffer = new byte[1024];  
  23. int len = -1;  
  24. while ((len = inStream.read(buffer)) != -1) {  
  25. 0, len);  
  26.         }  
  27.         outSteam.close();  
  28.         inStream.close();  
  29. return
  30.     }  
  31. }  

 你可以直接运行这个类,会看到流被转换的效果。

我们来写一个Socket客户端测试一下:

  1. package
  2. import
  3. import
  4. import
  5. public class
  6. public static void
  7. try
  8. new Socket("127.0.0.1", 8001);  
  9. // 开启保持活动状态的套接字
  10. true);  
  11. // 设置读取超时时间
  12. 30 * 1000);  
  13.             OutputStream ops = socket.getOutputStream();  
  14. "你好,我是崔素强!";  
  15.             ops.write(mess.getBytes());  
  16.             InputStream ips = socket.getInputStream();  
  17. byte[] rebyte = StreamTool.readStream(ips);  
  18. new
  19. "收到主机消息:"
  20.             socket.close();  
  21. catch
  22.             e.printStackTrace();  
  23.         }  
  24.     }  
  25. }  

 先运行DstService,然后运行客户端,看效果。会发现,控制台没有任何输出。经过调试发现,因为请求死在了

  1. while ((len = inStream.read(buffer)) != -1) {  

这行代码上面。这就是在网络应用中会造成的后果。那么如何解决呢?有的人给出了如下代码:

  1. int
  2. byte[] b = new byte[count];  
  3. in.read(b);  

可是在进行网络操作时往往出错,因为你调用available()方法时,对发发送的数据可能还没有到达,你得到的count是0。需要做如下修改,是我们的读取流方法改成如下:

  1. /**
  2.  * @功能 读取流
  3.  * @param inStream
  4.  * @return 字节数组
  5.  * @throws Exception
  6.  */
  7. public static byte[] readStream(InputStream inStream) throws
  8. int count = 0;  
  9. while (count == 0) {  
  10.         count = inStream.available();  
  11.     }  
  12. byte[] b = new byte[count];  
  13.     inStream.read(b);  
  14. return
  15. }  

下面你在运行,会看到服务端和客户端都收到了消息。 

关于InputStream.read(byte[] b)和InputStream.read(byte[] b,int off,int len)这两个方法都是用来从流里读取多个字节的,有经验的程序员就会发现,这两个方法经常 读取不到自己想要读取的个数的字节。比如第一个方法,程序员往往希望程序能读取到b.length个字节,而实际情况是,系统往往读取不了这么多。仔细阅读Java的API说明就发现了,这个方法 并不保证能读取这么多个字节,它只能保证最多读取这么多个字节(最少1个)。因此,如果要让程序读取count个字节,最好用以下代码:

  1. int count = 100;  
  2. byte[] b = new byte[count];  
  3. int readCount = 0; // 已经成功读取的字节的个数
  4. while
  5.     readCount += inStream.read(b, readCount, count - readCount);  
  6. }