首先请查看一下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异常或者到了数据流的结尾情况!
老规矩,最后是上传源代码!
请您到ITEYE看我的原创:http://cuisuqiang.iteye.com
或支持我的个人博客,地址:http://www.javacui.com
相关推荐
springboot 解决InputStream只能读取一次的问题
– 输入流:只能从中读取字节数据,而不能向其写出数据 – 输出流:只能向其写入字节数据,而不能从中读取数据 • 按照流所处理的数据类型 – 字节流:用于处理字节数据。 – 字符流:用于处理Unicode字符数据。 • ...
File file = new File("C:/Users/... //读取第一列数据 XSSFCell two = xssfRow.getCell(1); //读取第二列数据 XSSFCell three = xssfRow.getCell(2); //读取第三列数据 System.out.println(three); } } }
Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...
Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...
应用java的poi技术读取Excel数据到MySQL的实例源码,对学习Java编程技术有所帮助,与大家分享。
Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...
//从输入流中获取数据并以字节数组返回public class StreamTool { /** * 从输入流获取数据 * @param inputStream * @return * @throws Exception */ public static byte[] readInputStream(InputStream ...
程中产生迷惑, 以及出现问题也是在使用read ‘法输入数据时发生 的。 如果要使用read方法输入数据,应使用“System.in.read()”的形式。 在这个语句中,System是一个最终类,,不能用来产牛列象,它提供了 标准...
字节流:按照字节读取数据(InputStream、OutputStream) 字符流:按照字符读取数据(Reader、Writer) 功能不同: 节点流:可以直接从数据源或目的地读写数据。 处理流:不直接连接到数据源或目的地,是处理流的流...
Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...
Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...
Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...
数字证书:从文件中读取数字证书,生成文件输入流,输入文件为c:/mycert.cer,获取一个处理X.509证书的证书工厂…… Java+ajax写的登录实例 1个目标文件 内容索引:Java源码,初学实例,ajax,登录 一个Java+ajax写的...
变量和数据类型 整数运算 浮点数运算 布尔运算 字符和字符串 数组类型 流程控制 输入和输出 if判断 switch多重选择 while循环 do while循环 for循环 break和continue 数组操作 遍历数组 数组排序 ...
1. stream代表的是任何有能力产出数据的数据源,或是任何有能力接收数据的接收源。在Java的IO中,所有的stream(包括Input和Out stream)都包括两种类型: 1.1 以字节为导向的stream 以字节为导向的stream,表示以...
数据类型基础语法运算符 Java 执行控制流程条件语句 if 条件语句 if...else 条件语句if...else if 多分支语句switch 多分支语句 循环语句 while 循环语句do...while 循环for 循环语句 跳转语句 break 语句 continue ...
import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL...
* 从输入流读取数据为二进制字节数组. * @param streamIn * @return * @throws IOException */ public static byte[] readFileBinary(InputStream streamIn) throws IOException { BufferedInputStream...