java InputStream读取数据问题

首先请查看一下JavaAPI,可以看到InputStream读取流有三个方法,分别为read(),read(byte[] b),read(byte[] b, int off, int len)。其中read()方法是一次读取一个字节,鬼都知道效率是非常低的。所以最好是使用后面两个方法。

例如以下代码:

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

 

我们来测试一下:

Java代码   收藏代码
  1. public static void main(String[] args) {  
  2.     try {  
  3.         File file = new File("C:\\ceshi.txt");  
  4.         FileInputStream fin = new FileInputStream(file);  
  5.         byte[] filebt = readStream(fin);  
  6.         System.out.println(filebt.length);  
  7.     } catch (Exception e) {  
  8.         e.printStackTrace();  
  9.     }     
  10. }  

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

 

 

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

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

Java代码   收藏代码
  1. package com.service;  
  2. import java.net.*;  
  3. public class DstService {  
  4.     public static void main(String[] args) {  
  5.         try {  
  6.             // 启动监听端口 8001  
  7.             ServerSocket ss = new ServerSocket(8001);  
  8.             boolean bRunning = true;  
  9.             while (bRunning) {  
  10.                 // 接收请求  
  11.                 Socket s = ss.accept();  
  12.                 // 将请求指定一个线程去执行  
  13.                 new Thread(new DstServiceImpl(s)).start();  
  14.             }  
  15.         } catch (Exception e) {  
  16.             e.printStackTrace();  
  17.         }  
  18.     }  
  19. }  

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

Java代码   收藏代码
  1. package com.service;  
  2. import java.io.*;  
  3. import java.net.*;  
  4. import com.util.*;  
  5. public class DstServiceImpl implements Runnable {  
  6.     Socket socket = null;  
  7.     public DstServiceImpl(Socket s) {  
  8.         this.socket = s;  
  9.     }  
  10.     public void run() {  
  11.         try {  
  12.             InputStream ips = socket.getInputStream();  
  13.             OutputStream ops = socket.getOutputStream();  
  14.             while (true) {  
  15.                 byte[] bt = StreamTool.readStream(ips);  
  16.                 String str = new String(bt);  
  17.                 System.out.println("主机收到信息:" + str);  
  18.                 String restr = "你好,主机已经收到信息!";  
  19.                 ops.write(restr.getBytes());  
  20.                 ops.flush();  
  21.             }  
  22.         } catch (Exception e) {  
  23.             e.printStackTrace();  
  24.         }  
  25.     }  
  26. }  

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

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

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

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

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

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

Java代码   收藏代码
  1. while ((len = inStream.read(buffer)) != -1) {  

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

Java代码   收藏代码
  1. int count = in.available();  
  2. byte[] b = new byte[count];  
  3. in.read(b);  

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

Java代码   收藏代码
  1. /** 
  2.  * @功能 读取流 
  3.  * @param inStream 
  4.  * @return 字节数组 
  5.  * @throws Exception 
  6.  */  
  7. public static byte[] readStream(InputStream inStream) throws Exception {  
  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 b;  
  15. }  

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

 

 

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

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

 这样就能保证读取100个字节,除非中途遇到IO异常或者到了数据流的结尾情况!

老规矩,最后是上传源代码

 

请您到ITEYE看我的原创:http://cuisuqiang.iteye.com

或支持我的个人博客,地址:http://www.javacui.com


转自:http://cuisuqiang.iteye.com/blog/1434416


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java 中,可以通过多种方式获取 InputStream 的数据。InputStreamJava 中用于读取字节流的类。以下是三种常见的方法: 1. 使用 read() 方法读取 InputStream 中的数据。此方法将读取 InputStream 中的一个字节,并返回其对应的整数值。如果已经到达文件末尾,则返回 -1。可以通过以下方式读取 InputStream 的数据: InputStream inputStream = new FileInputStream("file.txt"); int data = inputStream.read(); while(data != -1) { // 处理读取的 data 值 data = inputStream.read(); } inputStream.close(); 2. 使用 BufferedInputStream 可以提高读取效率。此类允许你将 InputStream 包装成一个缓存区,提高数据读取的效率。以下是一个示例: InputStream inputStream = new FileInputStream("file.txt"); BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream); int data = bufferedInputStream.read(); while(data != -1) { // 处理读取的 data 值 data = bufferedInputStream.read(); } bufferedInputStream.close(); inputStream.close(); 3. 使用 Scanner 可以逐行读取文本内容。以下是一个示例: InputStream inputStream = new FileInputStream("file.txt"); Scanner scanner = new Scanner(inputStream); while(scanner.hasNextLine()) { String line = scanner.nextLine(); // 处理读取的每行数据 } scanner.close(); inputStream.close(); 以上是三种最常用的方法,你可以根据你的具体情况选择适合自己的方法来读取 InputStream 的数据。总之,无论使用哪种方法,务必在读取完毕后及时关闭 InputStream,释放资源。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值