java InputStream读取数据问题

来源:互联网 发布:不用网络看小说 编辑:程序博客网 时间:2024/06/07 02:29

转载地址:点击打开链接

首先请查看一下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) 

【从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中;如果 b 的长度为 0,则不读取任何字节并返回0;否则,尝试读取至少一个字节。读取的字节数最多等于b 的长度】

InputStream.read(byte[] b,int off,int len)

   b - 读入数据的缓冲区。

off - 数组 b 中将写入数据的初始偏移量。
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异常或者到了数据流的结尾情况!

阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 志鸟含义 志鸟的含义 志鸟村 志鸟什么意思 神级学霸志鸟村 唯我独法 志鸟村 未来图书馆 志鸟村 大医凌然 志鸟村 志鸿教育 志鸿 志鹏 志龙家族诞生 没忘 忘就忘 别忘 手机密码忘 忘爱哥 22344忘不 忘不了 忘不了你的爱但结局难更改 忘不了餐厅 忘了爱 我只是忘了忘记你 忘不了你的爱 忘了你忘了我 忘了 忘了我 忘了吧 忘了爱哥高清大图 忘不了你 wifi密码忘了 忘了我是谁 忘了吧算了吧 忘了去懂你 忘不了的伤 忘了她 行李箱密码忘了 忘不了鱼 22344忘不了 忘了爱图片