手机端小强原创文章,java小强个人博客站点
当前位置: 首页 >> NET >> java InputStream读取数据问题

java InputStream读取数据问题

49940 NET | 2014-6-18

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

/**
 * 读取流
 * 
 * @param inStream
 * @return 字节数组
 * @throws Exception
 */
public static byte[] readStream(InputStream inStream) throws Exception {
 ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
 byte[] buffer = new byte[1024];
 int len = -1;
 while ((len = inStream.read(buffer)) != -1) {
  outSteam.write(buffer, 0, len);
 }
 outSteam.close();
 inStream.close();
 return outSteam.toByteArray();
}

 

我们来测试一下:

public static void main(String[] args) {
 try {
  File file = new File("C:\\ceshi.txt");
  FileInputStream fin = new FileInputStream(file);
  byte[] filebt = readStream(fin);
  System.out.println(filebt.length);
 } catch (Exception e) {
  e.printStackTrace();
 } 
}

 

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

 

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

package com.service;
import java.net.*;
public class DstService {
 public static void main(String[] args) {
  try {
   // 启动监听端口 8001
   ServerSocket ss = new ServerSocket(8001);
   boolean bRunning = true;
   while (bRunning) {
    // 接收请求
    Socket s = ss.accept();
    // 将请求指定一个线程去执行
    new Thread(new DstServiceImpl(s)).start();
   }
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
}

 

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

package com.service;
import java.io.*;
import java.net.*;
import com.util.*;
public class DstServiceImpl implements Runnable {
 Socket socket = null;
 public DstServiceImpl(Socket s) {
  this.socket = s;
 }
 public void run() {
  try {
   InputStream ips = socket.getInputStream();
   OutputStream ops = socket.getOutputStream();
   while (true) {
    byte[] bt = StreamTool.readStream(ips);
    String str = new String(bt);
    System.out.println("主机收到信息:" + str);
    String restr = "你好,主机已经收到信息!";
    ops.write(restr.getBytes());
    ops.flush();
   }
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
}

 

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

package com.util;
import java.io.*;
public class StreamTool { 
 public static void main(String[] args) {
  try {
   File file = new File("C:\\ceshi.txt");
   FileInputStream fin = new FileInputStream(file);
   byte[] filebt = readStream(fin);
   System.out.println(filebt.length);
  } catch (Exception e) {
   e.printStackTrace();
  } 
 } 
 /**
  * @功能 读取流
  * @param inStream
  * @return 字节数组
  * @throws Exception
  */
 public static byte[] readStream(InputStream inStream) throws Exception {
  ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
  byte[] buffer = new byte[1024];
  int len = -1;
  while ((len = inStream.read(buffer)) != -1) {
   outSteam.write(buffer, 0, len);
  }
  outSteam.close();
  inStream.close();
  return outSteam.toByteArray();
 }
}

 

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

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

package com.client;
import java.io.*;
import java.net.*;
import com.util.*;
public class DstClient {
 public static void main(String[] args) {
  try {
   Socket socket = new Socket("127.0.0.1", 8001);
   // 开启保持活动状态的套接字
   socket.setKeepAlive(true);
   // 设置读取超时时间
   socket.setSoTimeout(30 * 1000);
   OutputStream ops = socket.getOutputStream();
   String mess = "你好,我是崔素强!";
   ops.write(mess.getBytes());
   InputStream ips = socket.getInputStream();
   byte[] rebyte = StreamTool.readStream(ips);
   String remess = new String(rebyte);
   System.out.println("收到主机消息:" + remess);
   socket.close();
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
}

 

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

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

 

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

int count = in.available();
byte[] b = new byte[count];
in.read(b);

 

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

/**
 * @功能 读取流
 * @param inStream
 * @return 字节数组
 * @throws Exception
 */
public static byte[] readStream(InputStream inStream) throws Exception {
 int count = 0;
 while (count == 0) {
  count = inStream.available();
 }
 byte[] b = new byte[count];
 inStream.read(b);
 return b;
}

 

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

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

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

 

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


推荐您阅读更多有关于“ InputStream 网络编程 JavaAPI available ”的文章

上一篇:JS绘图Flot应用-简单曲线图 下一篇:ByteBuffer 到底怎么用?网络编程中一点总结!

猜你喜欢

发表评论:

个人资料
blogger

java小强
没有思考,人生的路会越走越难!

搜索
分类
最新微语
  • 今天同学问我,最近还在写代码吗?我想了想,这个问题怎么回答呢,我好像确实很长时间,虽然写了一些,但是主要内容已经不是写代码了。然后再想想,自己也7年多了,这么多年了,我收获了什么,我的目标到底是什么。眼看就奔三了,人生啊,开启感叹模式。

    2017-03-30 22:52

  • 也许大家都已经注意到了,今年的房价,好多地方都是翻了一番,跟着就是,各地房东开始变相涨租。今年之所以搬走,就是为此,这两天同学也是如此。很多房东只认钱,别谈感情,伤钱。而对于这个城市来说,你怎么定位自己,你真把自己当成她的一份子?你来此为何?将来何去何从?自己掂量清楚。

    2016-12-05 10:03

  • 为什么一直不写了呢?因为当爸爸了,没空了。今年的冬天,有些寒冷,除了这寒冬带来的不适,更有因乐视公司遇到危机,而带来的同事别离。送别同事,看着空旷的工位,心中有些悲凉。临近年关,此时此刻,该怎么做,似乎不再是脑子一热那么简单了。

    2016-11-24 11:28

  • 已经请假,加上国庆,要很长一段时间不在北京了。919加班,搞的现在有点心累,胸闷,身体不适。看来,我要好好休息一下了。这几天有些冷,2016的冬天,一步步来了,各位亲友,记得添衣加粗啊。

    2016-09-23 17:29

  • 现在是真的有秋天的感觉了,晚上也不热了,白天也凉快了。再来点风,那酸爽,就有一种想出去防风的冲动了。不过因为最近广州的事情压着,我也没办法,搞的特别累,以前是天天加班不想有自由,现在是因为有事情了,被限制了自由。加上公司的一些事情,感觉日子特别的无聊。

    2016-08-31 17:39

  • 更多»

最新文章
热门文章
随机文章