字节流简介
public abstract class InputStreamextends Objectimplements Closeable
此抽象类是表示字节输入流的所有类的超类。
需要定义 InputStream 的子类的应用程序必须始终提供返回下一个输入字节的方法。
InputSteam的部分子类
其中颜色较深的是节点流,剩下的是过滤流,其中FilterInputStream在JDK中的定义为:包含其他一些输入流,它将这些流用作其基本数据源,可以直接传输数据或提供一些额外的功能,这个类本身并不经常被我们使用,常用的是它的子类。
读写数据的逻辑步骤为:
1、打开流
2、有信息需要操作
3、读写信息
4、关闭流
FileInputStream和FileOutputStream
FileInputStream 从文件系统中的某个文件中获取输入字节。哪些文件可用取决于主机环境。
FileInputStream 用于读取诸如图像数据之类的原始字节流。要读取字符流,请考虑使用 FileReader。
FileInputStream单独读取文件等时容易发生编码错误,一般用来读取图片,视频
如下代码,虽然输出没有问题,但是如果将缓存数组改为5个字节,就会出现控制台输出乱码,但对于文件的复制是没哟影响的
图片复制与文件复制
/**
*
*/
package io.input;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import org.junit.Test;
/**
* @author Administrator
*
*/
public class FileInputStreamTest {
static void p(Object s) {
System.out.println(s);
}
@Test
/**
* FileInputStream复制图片
*/
public void test1() {
InputStream is;
OutputStream os;
try {
is = new FileInputStream("C:\\Users\\Administrator\\Desktop\\md\\1.png");
os = new FileOutputStream("E:\\workspace\\fileTest\\copy.jpg");
int length = 0;
byte[] buffer = new byte[512];
while (-1 != (length=is.read(buffer))) {
os.write(buffer,0,length);
}
is.close();
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
/**
* FileInputStream复制文件
*/
public void test2() {
InputStream is;
OutputStream os;
try {
is = new FileInputStream("E:\\workspace\\fileTest\\a.txt");
os = new FileOutputStream("E:\\workspace\\fileTest\\test2\\b.txt");
int length = 0;
byte[] buffer = new byte[512];
while (-1 != (length=is.read(buffer))) {
String str = new String(buffer, "gbk");
p(str);
os.write(buffer,0,length);
}
is.close();
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
0.
0
a.txt保存为gbk编码,运行环境为utf-8编码,故需要进行转码
输出
这是流测试文件abcde
大河向东流
天上的星星参北斗
如果文件本来就存在会覆盖原文件内容
将输出流如下定义文件如果存在即可追加文件内容
os = new FileOutputStream(“E:\workspace\fileTest\test2\b.txt”,true);
1、每次读取的内容存放在buffer这个字节数组中,然后转换成String字符串打印在控制台中。
2、再将数组内容输出到指定文件中
3、因为一个文件内容有多少我们事先并不知道,所以在这里只能分批次读取,每次最多读取512个字节(即buffer数组定义的长度)。
4、length的作用是表示在最后一次读取的时候,读取的长度小于等于buffer数组的长度,while循环体执行结束后,下一次再来读取已经没有内容了,read方法在这个时候会返 回-1,然后跳出循环。
5、最后关闭流
以上代码虽然没有问题,但文件内容大于数组大小,很可能会出现读取的字符中文乱码,因为一种中文汉字不止一个字节,读取时可能会被数组截断,具体看下面的InputStreamReader
FilterInputStream和FilterOutputStream
FilterInputStream
FilterInputStream 的作用是用来“封装其它的输入流,并为它们提供额外的功能”。它的常用的子类有BufferedInputStream和DataInputStream。
(01) BufferedInputStream的作用就是为“输入流提供缓冲功能,以及mark()和reset()功能”。
(02) DataInputStream 是用来装饰其它输入流,它“允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型”。应用程序可以使用DataOutputStream(数据输出流)写入由DataInputStream(数据输入流)读取的数据。
FilterOutputStream
FilterOutputStream 的作用是用来“封装其它的输出流,并为它们提供额外的功能”。它主要包括BufferedOutputStream, DataOutputStream和PrintStream。
(01) BufferedOutputStream的作用就是为“输出流提供缓冲功能”。
(02) DataOutputStream 是用来装饰其它输出流,将DataOutputStream和DataInputStream输入流配合使用,“允许应用程序以与机器无关方式从底层输入流中读写基本 Java 数据类型”。
(03) PrintStream 是用来装饰其它输出流。它能为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。
BufferedInputStream和BufferedOutputStream
BufferedInputStream(InputStream in, int size)
BufferedInputStream就是为了创建个指定缓冲区大小的 BufferedInputStream 并保存其参数
介绍FileInputStream和FileOutputStream的例子中,使用了一个byte数组来作为数据读入的缓冲区,以文件存取为例,硬盘存取的速度远低于内存中的数据存取速度。为了减少对硬盘的存取,通常从文件中一次读入一定长度的数据,而写入时也是一次写入一定长度的数据,这可以增加文件存取的效率。
java.io.BufferedInputStream与java.io.BufferedOutputStream可以为InputStream、OutputStream类的对象增加缓冲区功能。
BufferedInputStream的数据成员buf是一个位数组,默认为2048字节。当读取数据来源时,例如文件,BufferedInputStream会尽量将buf填满。当使用read()方法时,实际上是先读取buf中的数据,而不是直接对数据来源作读取。当buf中的数据不足时,BufferedInputStream才会再实现给定的InputStream对象的read()方法,从指定的装置中提取数据。
BufferedOutputStream的数据成员buf是一个位数组,默认为512字节。当使用write()方法写入数据时,实际上会先将数据写至buf中,当buf已满时才会实现给定的OutputStream对象的write()方法,将buf数据写至目的地,而不是每次都对目的地作写入的动作。
@Test
/**
* BufferedInputStream和BufferedOutputStream
*/
public void test3() {
OutputStream os;
InputStream is;
try {
is = new FileInputStream("E:\\workspace\\fileTest\\a.txt");
os = new FileOutputStream("E:\\workspace\\fileTest\\test2\\b.txt");
InputStream bis = new BufferedInputStream(is);
OutputStream bos = new BufferedOutputStream(os);
byte[] buffer = new byte[512];
while(bis.read(buffer)!=-1){
bos.write(buffer);
}
bos.close();
os.close();
bis.close();
is.close();
} catch (Exception e) {
e.printStackTrace();
}
}
看到以上代码,不少人可能有疑问,既然缓存流已经有缓存数组了,怎么还需要定义字节数组?
这是不同的,以前是每次你读取时,系统执行读取操作把数据读出来,你指定读一个字节那就读一个字节,指定一个数组那就读一个数组的,程序和数据的读取效率有非常大的关系。
当你创建bufferedinputstream,后他会立即去读数据然后放到jvm管理的内存里,
每次你读取时,不会再去系统中读取,而是去内存中读取数据,之后再判断内存中剩的还多不,不多就再由它去指挥系统读取操作,不论你是读一个字节还是一个数组,系统都不一定会去操作硬盘。程序和数据读取的效率关联较小了。
两个数组的存在都是为了提高读写效率
流的close问题
@Test
/**
* BufferedInputStream和BufferedOutputStream
* 没有调用close方法
* 结果为,复制文件的内容为空,因为在缓存数组中没有close调用时flush掉
*/
public void test4() {
OutputStream os;
InputStream is;
try {
is = new FileInputStream("E:\\workspace\\fileTest\\a.txt");
os = new FileOutputStream("E:\\workspace\\fileTest\\test2\\b.txt");
InputStream bis = new BufferedInputStream(is);
OutputStream bos = new BufferedOutputStream(os);
byte[] buffer = new byte[512];
while(bis.read(buffer)!=-1){
bos.write(buffer);
}
} catch (Exception e) {
e.printStackTrace();
}
}
当不关闭流时,文件内容还在缓存中,没有输出出去,当调用close方法时会调用flush方法来刷新
而flush在JDK中的定义为:刷新此缓冲的输出流。这迫使所有缓冲的输出字节被写出到底层输出流中
DataInputStream和DataOutputStream
数据输出流允许应用程序以适当方式将基本 Java 数据类型写入输出流中。然后,应用程序可以使用数据输入流将数据读入。
@Test
/**
* DataInputStream和 DataOutputStream
* 直接读写数据类型
*/
public void test5() {
OutputStream os;
InputStream is;
try {
is = new FileInputStream("E:\\workspace\\fileTest\\test2\\b.txt");
os = new FileOutputStream("E:\\workspace\\fileTest\\test2\\b.txt");
DataInputStream dis = new DataInputStream(is);
DataOutputStream dos = new DataOutputStream(os);
byte by = 1;
String str = "String中";
int i=100;
dos.writeByte(by);
dos.writeUTF(str);
dos.writeInt(i);
//读取的顺序不能乱,必须和写入的数据类型一致
p(dis.readByte());
p(dis.readUTF());
p(dis.readInt());
} catch (Exception e) {
e.printStackTrace();
}
}
writeUTF(Stirng str)将字符串以utf-8的编码写入
DataInputStream和 DataOutputStream的写入和读取的数据类型不能乱,不然会出错
ByteArrayInputStream和ByteArrayOutputStream
流的来源或目的地并不一定是文件,也可以是内存中的一块空间,例如一个字节数组。java.io.ByteArrayInputStream、java.io.ByteArrayOutputStream就是将字节数组当作流输入来源、输出目的地的类。
java.io.ByteArrayInputStream将一个字节数组当作流输入的来源,而java.io.ByteArrayOutputStream则可以将一个字节数组当作流输出目的地。
ByteArrayInputStream与ByteArrayOutputStream类用于以IO流的方式来完成对字节数组的内容的读写,来支持类似内存虚拟文件或者内存映像文件的功能。
例如:
public static void transform(InputStream in, OutputStream out) {
int ch = 0;
try {
while ((ch = in.read()) != -1) {
out.write(ch);
} // close while
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
/**
* ByteArrayInputStream和ByteArrayOutputStream 直接读写数据类型
*/
public void test6() {
String str = "abcdef";
ByteArrayInputStream in = new ByteArrayInputStream(str.getBytes());
ByteArrayOutputStream out = new ByteArrayOutputStream();
transform(in, out);
byte[] result = out.toByteArray();
System.out.println(out);
System.out.println(new String(result));
transform(System.in, System.out); // 从键盘读,输出到显示器
}
以上代码完成了将字符串以字节方式输出,且可以在控制台输入并复制输出
有时候我们需要对同一个InputStream对象使用多次。比如,既要把数据显示到前台(第一次读取),又想把数据写进文件缓存到本地(第二次读取)。
但第一次读取InputStream对象后,第二次再读取时可能已经到Stream的结尾了(EOFException)或者Stream已经close掉了。
而InputStream对象本身不能复制,因为它没有实现Cloneable接口。此时,可以先把InputStream转化成ByteArrayOutputStream,后面要使用InputStream对象时,再从ByteArrayOutputStream转化回来就好了。代码实现如下:
@Test
/**
* ByteArrayInputStream和ByteArrayOutputStream
* 真正的巧妙用法
*/
public void test7() {
try{
InputStream input = new FileInputStream("E:\\workspace\\fileTest\\test2\\b.txt");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = input.read(buffer)) != -1 ) {
baos.write(buffer, 0, len);
}
baos.flush();
//TODO:显示到前台
InputStream stream1 = new ByteArrayInputStream(baos.toByteArray());
OutputStream out = System.out;
byte[] buffer2 = new byte[1024];
int count=0;
while((count=stream1.read(buffer2))!=-1){
out.write(buffer2,0,count);
}
//TODO:本地缓存
InputStream stream2 = new ByteArrayInputStream(baos.toByteArray());
OutputStream out2 = new FileOutputStream("E:\\workspace\\fileTest\\a.txt");
byte[] buffer3 = new byte[1024];
int count2=0;
while((count2=stream2.read(buffer2))!=-1){
out2.write(buffer2,0,count2);
}
out2.close();
out.close();
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
同一个流,进行了两次的输出,不必进行两次读取,通过ByteArrayInputStream和ByteArrayOutputStream的转换
//TODO:显示到前台
InputStream stream1 = new ByteArrayInputStream(baos.toByteArray());
//TODO:本地缓存
InputStream stream2 = new ByteArrayInputStream(baos.toByteArray());
BufferedOutputStream 和 ByteArrayOutputStream的区别
1、BufferedOutputStream会首先创建一个默认的容器量, capacity = 8192 = 8KB, 每次在写的时候都会去比对capacity是否还够用, 如果不够用的时候, 就flushBuffer(), 把buf中的数据写入对应的outputStream中, 然后将buf清空, 一直这样等到把内容写完. 在这过程中主要起到了一个数据缓冲的功能.
2、普通的OutputStream, 例如ByteArrayOutputStream也会首先创建一个默认的容器量, capacity = 32 = 32b, 每次在写的时候都会去比对capacity是否还够用, 如果不够用的时候, 就重新创建buf的容量, 一直等到内容写完, 这些数据都会一直处于内存中.
总结 : 当你资源不足够用时,选择BufferedOutputStream是最佳的选择, 当你选择快速完成一个作业时,可以选择ByteArrayOutputStream之类的输出流
write(byte b[], int off, int len)与write(byte b[])的区别
write(byte b[], int off, int len)表示:
b 这一次写的数据
off 这次从b的第off开始写
len 这次写的长度。
在进行写文件的时候有时候返现,通过write(byte b[])方式写文件比原来的文件大一些。因为
write(byte b[])的实现是
public void write(byte b[]) throws IOException {
write(b, 0, b.length);
}
其本质会获取字节数组的长度,最后一次如果内容不足填充数组会造成写入数据还是数组的长度
一般我们会这样写入数据
byte input[] = new byte[1024];
while ((brin.read(input))!= -1) {
bout.write(input);
}
但应该改为有多少数据写多少数据
byte input[] = new byte[1024*5];
int count;
while ((count=brin.read(input))!= -1) {
bout.write(input,0,count);
}
管道(PipedOutputStream和PipedInputStream)
/**
*
*/
package io.input;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
/**
* @author Administrator
*
*/
public class PipedStreamTest {
public static void main(String[] args) {
Sender sender = new Sender();
Receiver receiver = new Receiver();
PipedOutputStream outStream = sender.getOutStream();
PipedInputStream inStream = receiver.getInStream();
try {
// inStream.connect(outStream); // 与下一句一样
outStream.connect(inStream);
} catch (Exception e) {
e.printStackTrace();
}
receiver.start();
sender.start();
}
}
class Sender extends Thread {
private PipedOutputStream outStream = new PipedOutputStream();
public PipedOutputStream getOutStream() {
return outStream;
}
public void run() {
writeShortMessage();
//writeLongMessage();
}
// 向“管道输出流”中写入一则较简短的消息:"this is a short message"
private void writeShortMessage() {
String strInfo = "this is a short message";
try {
outStream.write(strInfo.getBytes());
outStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// 向“管道输出流”中写入一则较长的消息
private void writeLongMessage() {
StringBuilder sb = new StringBuilder();
// 通过for循环写入1020个字节
for (int i = 0; i < 102; i++)
sb.append("0123456789");
// 再写入26个字节。
sb.append("abcdefghijklmnopqrstuvwxyz");
// str的总长度是1020+26=1046个字节
String str = sb.toString();
try {
// 将1046个字节写入到“管道输出流”中
outStream.write(str.getBytes());
outStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Receiver extends Thread {
private PipedInputStream inStream = new PipedInputStream();
public PipedInputStream getInStream() {
return inStream;
}
public void run() {
readMessageOnce() ;
//readMessageContinued() ;
}
// 从“管道输入流”中读取1次数据
public void readMessageOnce() {
// 虽然buf的大小是2048个字节,但最多只会从“管道输入流”中读取1024个字节。
// 因为,“管道输入流”的缓冲区大小默认只有1024个字节。
byte[] buf = new byte[2048];
try {
int len = inStream.read(buf);
System.out.println(new String(buf, 0, len));
inStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// 从“管道输入流”读取>1024个字节时,就停止读取
public void readMessageContinued() {
int total = 0;
while (true) {
byte[] buf = new byte[1024];
try {
int len = inStream.read(buf);
total += len;
System.out.println(new String(buf, 0, len));
// 若读取的字节总数>1024,则退出循环。
if (total > 1024)
break;
} catch (IOException e) {
e.printStackTrace();
}
}
try {
inStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// 从“管道输入流”读取所有内容
public void readMessageContinue() {
int total = 0;
byte[] buf = new byte[1024];
try {
int len ;
while((len=inStream.read(buf))!=-1){
System.out.println(new String(buf, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
}
try {
inStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
输出
this is a short message
说明:
(01)
in.connect(out);
将“管道输入流”和“管道输出流”关联起来。查看PipedOutputStream.java和PipedInputStream.java中connect()的源码;我们知道 outStream.connect(inStream); 等价于 inStream.connect(outStream);
(02)
sender.start(); // 启动“Sender”线程
receiver.start(); // 启动“Receiver”线程
注意管道输入流的缓冲区默认大小是1024个字节。所以,最多只能写入1024个字节。
private static final int DEFAULT_PIPE_SIZE = 1024;
public PipedInputStream() {
initPipe(DEFAULT_PIPE_SIZE);
}
详细了解请阅读java io系列04之 管道(PipedOutputStream和PipedInputStream)的简介,源码分析和示例
退回输入流PushbackInputStream
PushBackInputStream的实现逻辑比较清晰
内部有一个缓冲区,你要是回退了我就往里面写入数据
每次的数据读取都是先看看缓冲区里面有没有数据,有的话就先读取回退缓冲区的
否则,就再去使用实际的流去进行读取
如果从来不曾回退过,那么好像什么都一样,还是使用原来的InputStream 进行读取
PushBackInputStream 不支持标记点相关的操作
void unread(int b)
void unread(byte[] buffer)
void unread(byte[] buffer,int offset,int numBytes)
第一种形式回推b的低字节,这会使得后续的read()调用会把这个字节再次读取出来。第二种形式回推buffer中的字节。第三种形式回推buffer中从offset开始的numBytes个字节。当回推缓存已满时,如果试图回推字节,就会抛出IOException异常。
第一种测试:
@Test
/**
* 退回输入流PushbackInputStream
*/
public void test8() {
String str = "abcdef";
try {
ByteArrayInputStream in = new ByteArrayInputStream(str.getBytes());
PushbackInputStream pbin = new PushbackInputStream(in) ;
int n;
int i=0;
while ((n = pbin.read()) != -1) {
i++;
System.out.println((char) n+":"+i);
if('b' == n) pbin.unread('U');
}
} catch (Exception e) {
// TODO: handle exception
}
}
输出
a:1
b:2
U:3
c:4
d:5
e:6
f:7
第二种测试:
@Test
/**
* 退回输入流PushbackInputStream
*/
public void test9() {
String str = "abcdefg";
try {
/*
* PushbackInputStream pbin = new PushbackInputStream(in,3)
* 这个构造函数创建的对象一次可以回推一个缓存
*/
ByteArrayInputStream in = new ByteArrayInputStream(str.getBytes());
PushbackInputStream pbin = new PushbackInputStream(in,3);
int n;
int i = 0;
byte[] buffer = new byte[3];
while ((n = pbin.read(buffer)) != -1) {
i++;
String read = new String(buffer);
System.out.println(read + ":" + i);
if (read.equals("abc")){
pbin.unread(new byte[]{'M','N','O'});
}
buffer = new byte[3];
}
} catch (Exception e) {
// TODO: handle exception
}
}
输出
abc:1
MNO:2
def:3
g :4
注释循环中的 buffer = new byte[3];
输出为
abc:1
MNO:2
def:3
gef:4
造成这种情况原因是缓存区数组是从后往前填充,当不重新在循环中定义新的数组对象时,循环中使用的一直是同一个数组对象,最后一次读取的内容覆盖上一次读取的内容,但是,由于数据无法填充整个数组,所以后面的数据就没有被覆盖,故保留为上一次读取的内容
第三种种测试:
@Test
/**
* 退回输入流PushbackInputStream
*/
public void test10() {
String s = "abcdefg";
/*
* PushbackInputStream pbin = new PushbackInputStream(in,4)
* 这个构造函数创建的对象一次可以回推一个缓存
*/
try {
ByteArrayInputStream in = new ByteArrayInputStream(s.getBytes());
PushbackInputStream pbin = new PushbackInputStream(in, 4);
int n;
int i = 0;
byte[] buffer = new byte[4];
while ((n = pbin.read(buffer)) != -1) {
i++;
System.out.println(new String(buffer)+":"+i);
// 取回推缓存中的一部分数据
if (new String(buffer).equals("abcd")) {
pbin.unread(buffer, 0, 3);
}
buffer = new byte[4];
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
abce:1
abce:2
fg :3
PushbackInputStream pbin = new PushbackInputStream(in,4)如果将4改为2,就是将回推数组的大小改为2个字节,那么pbin.unread(buffer, 0, 3);时就会出错:
java.io.IOException: Push back buffer is full
回推数组已满,默认回推数组大小为1
public PushbackInputStream(InputStream in, int size) {
super(in);
if (size <= 0) {
throw new IllegalArgumentException("size <= 0");
}
this.buf = new byte[size];
this.pos = size;
}
public PushbackInputStream(InputStream in) {
this(in, 1);
}
注:PushbackInputStream对象会使得InputStream对象(用于创建PushbackInputStream对象)的mark()或reset()方法无效。对于准备使用mark()或reset()方法的任何流来说,都应当使用markSupported()方法进行检查
合并流SequenceInputStream
输入合并流,将多个流进行逻辑串联(合并变成一个流,操作起来很方便)
public SequenceInputStream(Enumeration<? extends InputStream> e)
通过记住参数来初始化新创建的 SequenceInputStream,该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。将按顺序读取由该枚举生成的输入流,以提供从此 SequenceInputStream 读取的字节。在用尽枚举中的每个输入流之后,将通过调用该流的 close 方法将其关闭。
参数:
e - 输入流的一个枚举。
另请参见:
Enumeration
public SequenceInputStream(InputStream s1, InputStream s2)
通过记住这两个参数来初始化新创建的 SequenceInputStream(将按顺序读取这两个参数,先读取 s1,然后读取 s2),以提供从此 SequenceInputStream 读取的字节。
参数:
s1 - 要读取的第一个输入流。
s2 - 要读取的第二个输入流。
@Test
/**
* 合并流SequenceInputStream进而SequenceOutputStream
*/
public void test11() {
String str1 = "你好,";
String str2 = "中国,";
String str3 = "我爱你";
ByteArrayInputStream bis1 = new ByteArrayInputStream(str1.getBytes());
ByteArrayInputStream bis2 = new ByteArrayInputStream(str2.getBytes());
ByteArrayInputStream bis3 = new ByteArrayInputStream(str3.getBytes());
SequenceInputStream seq = new SequenceInputStream(bis1, bis2);
SequenceInputStream seq2 = new SequenceInputStream(seq, bis3);
try {
int len = 0;
byte buf[] = new byte[10];
while ((len = seq2.read(buf)) != -1) {
System.out.println(new String(buf));
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
/**
* 合并流SequenceInputStream进而SequenceOutputStream
*/
public void test12() {
String str1 = "你好,";
String str2 = "中国,";
String str3 = "我爱你";
ByteArrayInputStream bis1 = new ByteArrayInputStream(str1.getBytes());
ByteArrayInputStream bis2 = new ByteArrayInputStream(str2.getBytes());
ByteArrayInputStream bis3 = new ByteArrayInputStream(str3.getBytes());
ArrayList<InputStream> c = new ArrayList<InputStream>();
c.add(bis1);
c.add(bis2);
c.add(bis3);
Enumeration<InputStream> em = Collections.enumeration(c);
SequenceInputStream seq = new SequenceInputStream(em);
try {
int len = 0;
byte buf[] = new byte[10];
while ((len = seq.read(buf)) != -1) {
System.out.println(new String(buf));
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
/**
* 合并流SequenceInputStream进而SequenceOutputStream
*/
public void test13() {
String str1 = "你好,";
String str2 = "中国,";
String str3 = "我爱你";
ByteArrayInputStream bis1 = new ByteArrayInputStream(str1.getBytes());
ByteArrayInputStream bis2 = new ByteArrayInputStream(str2.getBytes());
ByteArrayInputStream bis3 = new ByteArrayInputStream(str3.getBytes());
Vector<InputStream> v = new Vector<InputStream>();
v.add(bis1);
v.add(bis2);
v.add(bis3);
Enumeration<InputStream> en = v.elements();
SequenceInputStream seq = new SequenceInputStream(en);
try {
int len = 0;
byte buf[] = new byte[10];
while ((len = seq.read(buf)) != -1) {
System.out.println(new String(buf));
}
} catch (Exception e) {
e.printStackTrace();
}
}
闲言碎语
本文章代码仅供流功能测试,存在很多问题,比如流的关闭,异常的捕获,参考代码时请注意
参考
java io系列14之 DataInputStream(数据输入流)的认知、源码和示例
java io系列02之 ByteArrayInputStream的简介,源码分析和示例(包括InputStream)
java io系列04之 管道(PipedOutputStream和PipedInputStream)的简介,源码分析和示例