`
cuisuqiang
  • 浏览: 3960187 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
3feb66c0-2fb6-35ff-968a-5f5ec10ada43
Java研发技术指南
浏览量:3670028
社区版块
存档分类
最新评论

java InputStream读取数据问题

    博客分类:
  • JDK
阅读更多

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

 

15
1
分享到:
评论
29 楼 jiafuwei0407 2017-04-21  
学习了! 用了这个方法,就不会阻塞了
28 楼 tanghai753 2016-03-17  
YaenLi 写道
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; 


这段代码只能确保读到一段流吧,如果是分段发送的怎么办?

----同问~请教博主是否存在此情况,以及应该如何处理~~谢谢
27 楼 YaenLi 2016-03-10  
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; 


这段代码只能确保读到一段流吧,如果是分段发送的怎么办?
26 楼 YaenLi 2016-03-10  
 
25 楼 kanding 2015-11-07  
wdhdmx 写道
三个read 方法都是一个字节一个字节的读,后两个read方法里面是调用第一个read,效率似乎应该都一样。

看了代码,后两个方法是封装了第一个方法,但是如果你自己写的话,估计会更慢。
24 楼 2047699523 2015-04-08  
请参考代码:java通过InputStream读取和写入文件操作实例代码,下载地址:http://www.zuidaima.com/share/1758442014903296.htm
23 楼 cuisuqiang 2013-11-25  
mvpstevenlin 写道
楼主有个问题, 你把读数据改成
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; 

那你要在哪里写数据呢 ?

拿到Output就可以写
22 楼 mvpstevenlin 2013-11-17  
楼主有个问题, 你把读数据改成
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; 

那你要在哪里写数据呢 ?
21 楼 cuisuqiang 2013-07-25  
windseamless 写道
windseamless 写道
windseamless 写道
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;  
}  
  如果是这样读取的话,比如在接受心跳数据的时候,发送信条时间间隔比较长的情况下,这个循环一直在执行,去、这样就会造成电脑非常卡

windseamless 写道
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;  
}  
  如果是这样读取的话,比如在接受心跳数据的时候,发送心跳时间间隔比较长的情况下,这个循环一直在执行,这样就会造成电脑非常卡


你说的这个方法很好,这样的话就可以解决死循环问题

确实应该增加个休眠
20 楼 windseamless 2013-07-25  
windseamless 写道
windseamless 写道
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;  
}  
  如果是这样读取的话,比如在接受心跳数据的时候,发送信条时间间隔比较长的情况下,这个循环一直在执行,去、这样就会造成电脑非常卡

windseamless 写道
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;  
}  
  如果是这样读取的话,比如在接受心跳数据的时候,发送心跳时间间隔比较长的情况下,这个循环一直在执行,这样就会造成电脑非常卡


你说的这个方法很好,这样的话就可以解决死循环问题
19 楼 jadyer 2013-07-25  
windseamless 写道
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;  
}  
  如果是这样读取的话,比如在接受心跳数据的时候,发送信条时间间隔比较长的情况下,这个循环一直在执行,去、这样就会造成电脑非常卡



可以在里面加个Thread.sleep(200);,然后在定个变量,int k = 0,线程没休眠一次k++,直到k大于等于一个数值,比如15,就return;
即3s内仍无数据,就咔嚓连接
18 楼 windseamless 2013-07-18  
windseamless 写道
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;  
}  
  如果是这样读取的话,比如在接受心跳数据的时候,发送信条时间间隔比较长的情况下,这个循环一直在执行,去、这样就会造成电脑非常卡

windseamless 写道
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;  
}  
  如果是这样读取的话,比如在接受心跳数据的时候,发送心跳时间间隔比较长的情况下,这个循环一直在执行,这样就会造成电脑非常卡

17 楼 windseamless 2013-07-18  
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;  
}  
  如果是这样读取的话,比如在接受心跳数据的时候,发送信条时间间隔比较长的情况下,这个循环一直在执行,去、这样就会造成电脑非常卡
16 楼 cuisuqiang 2013-06-14  
lsh009 写道
cuisuqiang 写道
lsh009 写道
cuisuqiang 写道
lsh009 写道
顶,最近在做socket连接,就是read inputstream 死锁了,谢谢

你可以看看mina框架

你好,服务器端用mina,客户端不要mina用普通的socket或者nio应该可以的吧?

没有问题,如果你用mina,别人就必须用mina,那做C和C++的岂不是要死

呵呵,确认一下,不然以后有什么问题会很麻烦,毕竟客户端不是我们这边做的,现在只做服务端,再问个问题额,接收到数据 我需要比较长时间处理数据,再返回,用mina需要自己实现多线程吗,还是mina本身实现了,不做多线程的话,后续来的数据,会卡住等待前一个数据处理完才处理吗?谢谢

我建议你呢做个实验,在Mina收到数据时打印一条信息,然后长期休眠,然后再模拟发一条数据,看看能不能打印
15 楼 lsh009 2013-06-11  
cuisuqiang 写道
lsh009 写道
cuisuqiang 写道
lsh009 写道
顶,最近在做socket连接,就是read inputstream 死锁了,谢谢

你可以看看mina框架

你好,服务器端用mina,客户端不要mina用普通的socket或者nio应该可以的吧?

没有问题,如果你用mina,别人就必须用mina,那做C和C++的岂不是要死

呵呵,确认一下,不然以后有什么问题会很麻烦,毕竟客户端不是我们这边做的,现在只做服务端,再问个问题额,接收到数据 我需要比较长时间处理数据,再返回,用mina需要自己实现多线程吗,还是mina本身实现了,不做多线程的话,后续来的数据,会卡住等待前一个数据处理完才处理吗?谢谢
14 楼 cuisuqiang 2013-06-11  
lsh009 写道
cuisuqiang 写道
lsh009 写道
顶,最近在做socket连接,就是read inputstream 死锁了,谢谢

你可以看看mina框架

你好,服务器端用mina,客户端不要mina用普通的socket或者nio应该可以的吧?

没有问题,如果你用mina,别人就必须用mina,那做C和C++的岂不是要死
13 楼 lsh009 2013-06-11  
cuisuqiang 写道
lsh009 写道
顶,最近在做socket连接,就是read inputstream 死锁了,谢谢

你可以看看mina框架

你好,服务器端用mina,客户端不要mina用普通的socket或者nio应该可以的吧?
12 楼 cuisuqiang 2013-06-07  
lsh009 写道
顶,最近在做socket连接,就是read inputstream 死锁了,谢谢

你可以看看mina框架
11 楼 lsh009 2013-06-07  
顶,最近在做socket连接,就是read inputstream 死锁了,谢谢
10 楼 Sser渐渐 2013-04-16  
最近在写一个邮件代理的时候在pop协议取回邮件的时候遇到这个问题,得到解释后问题解决,很开心,非常感谢

相关推荐

    java 读取串口数据(绝对可使用)

    Java 读取串口数据是Java编程中一个重要的部分,特别是在物联网(IoT)设备通信、嵌入式系统以及工业自动化等领域。RXTX库是一个流行的开源Java库,用于实现与串行端口(COM口)和并行端口的交互。在本教程中,我们将...

    springboot 解决InputStream只能读取一次的问题

    这样,我们就成功地解决了Spring Boot中`InputStream`只能读取一次的问题,使得我们可以多次读取并处理请求数据,无论是用于文件上传、消息解析还是其他需要多次读取的场景。在实际项目中,根据具体需求,可能还需要...

    JAVA串口采集传感器数据

    5. **读写数据**:使用`InputStream`和`OutputStream`进行串口数据的读取和写入。 ```java InputStream in = serialPort.getInputStream(); OutputStream out = serialPort.getOutputStream(); byte[] buffer ...

    java.io.Reader 和 java.io.InputStream 的区别

    `java.io.Reader`和`java.io.InputStream`是Java标准库中处理输入数据的核心类,它们分别针对字符流和字节流提供了基础的支持。 #### `java.io.Reader`:字符流的读取器 `java.io.Reader`是所有字符输入流的超类。...

    Java实现inputstream流的复制代码实例

    在 Java 中,InputStream 是一个抽象类,用于读取字节流。它是 Java IO 体系中最基本的输入流接口。InputStream 的主要方法有: * `read()`:读取一个字节 * `read(byte[] b)`:读取多个字节到字节数组中 * `close...

    读取串口数据,java写的

    总的来说,这个Java串口读取程序是实现与硬件设备之间串行通信的一个实例,通过解析`SerialPortDemo-master`中的代码,我们可以深入了解Java如何与硬件进行串口通信,以及如何处理相关的数据传输问题。在实际应用中...

    Java流(文件读写操作)

    - **输入流**:主要用于从数据源读取数据。输入流只能从中读取数据,而不能向其中写入数据。例如,`FileInputStream`用于从文件中读取字节数据。 - **输出流**:主要用于向目的地写入数据。输出流只能向其中写入数据...

    java 获取json网页数据

    在Java编程中,获取JSON网页数据是常见的任务,特别是在处理Web API或者进行数据抓取时。JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,因其简洁和高效而广泛被采用。本实例将深入讲解如何使用...

    Java中InputStream类.pdf

    作为抽象类,`InputStream`定义了一系列基本的方法来读取字节数据,这些方法由其子类进行具体实现。`InputStream`的出现是为了提供一个统一的接口,方便开发者处理各种不同类型的输入数据流。 **1. 抽象类与继承...

    java使用Socket类接收和发送数据

    - 获取输入流:同样,通过`Socket`的`getInputStream()`方法获取一个`InputStream`,然后利用`DataInputStream`或`BufferedReader`等类读取服务器返回的数据。 ```java InputStream inputStream = socket....

    java读取sqlserver image字段.docx

    然而,如何有效地从数据库中读取这些二进制数据,并将其转换为可用的格式,如图像文件,则是一个常见的技术问题。本文将详细介绍如何使用Java语言读取SQL Server中的`IMAGE`字段,并将其转换为图片文件。 #### 二、...

    Java解析大数据量Excel,可解析1048576行excel

    2. **迭代读取**: 使用`RowIterator`或`CellIterator`进行迭代读取,而不是一次性获取所有行或所有单元格。这可以避免一次性加载大量数据,尤其是在处理百万行时。 3. **优化内存使用**: 设置适当的内存阈值,例如...

    java读取dlt645所需文件

    如果你的DLL文件包含了读取DLT645数据的原生函数,那么你需要使用这些技术将Java代码与DLL功能关联起来。 3. **Jar包**:Java Archive(JAR)文件是Java平台特有的归档格式,用于打包类文件、资源文件等。如果你的...

    将输出流OutputStream转化为输入流InputStream的方法

    // 从InputStream读取数据 byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = in.read(buffer)) != -1) { System.out.print(new String(buffer, 0, bytesRead)); } } catch (IOException ...

    Java字节流数据逐行读取(readLine)

    总结来说,虽然Java的字节流不直接支持`readLine()`方法,但通过结合`InputStreamReader`和`BufferedReader`,我们可以方便地实现字节流数据的逐行读取。在处理文本文件时,正确选择字符编码并确保资源的有效管理是...

    java 使用socked接收chunck分块数据

    Java的Socket API提供了一个InputStream,我们可以从这个输入流中读取接收到的数据。在chunked模式下,数据被分为多个块,每个块都有一个十六进制的大小前缀,后面跟着块的实际内容,最后是一块大小为0的块表示数据...

    完美解决java读取excel内存溢出问题.rar

    总结来说,解决Java读取Excel内存溢出问题,关键在于合理利用资源、优化代码逻辑以及选择适合的API,如Apache POI的SXSSF。通过这些方法,我们可以在不显著增加系统资源负担的情况下,高效地处理大Excel文件。

    Java应用程序读取图片内容.zip

    在Java编程语言中,读取图片内容是一项常见的任务,尤其在开发图形用户界面(GUI)应用、处理图像数据或进行图像分析时。本教程将详细解释如何使用Java来读取和处理图片。以下是一些核心知识点: 1. **Java Image I...

Global site tag (gtag.js) - Google Analytics