Java学习笔记-08【IO】【上】
在Java中,应该按照以下顺序关闭流:
- 先关闭最里层的流,然后逐层向外关闭。
- 在关闭流之前,应该先判断流是否为null。
- 先关闭输出流,再关闭输入流。
(本文中代码已忽略,使用时请自行修改)
IO流按照操作数据的不同,分为字节流和字符流,按照数据传输方向分为输入流和输出流。
字节流
计算机中,所有文件都是以二进制(字节)形式存在,IO流中针对字节的输入输出提供了一系列的流称为字节流。
在JDK中提供了两个抽象类:InputStream和OutputStream,它们是字节流的顶级父类。
InputStream输入流和OutputStream输出流
InputStream的常用方法
方法声明 | 功能描述 |
---|---|
int read() | 从输入流读取一个8位的字节,把它转换为0~255之间的整数,并返回这一整数 |
int read(byte[] b) | 从输入流读取若干字节,把它们保存到参数b指定的字节数组中,返回的整数表示读取字节数 |
int read(byte[] b,int off,int len) | 从输入流读取若干字节,把它们保存到参数b指定的字节数组中,off指定字节数组开始保存数据的起始下标,len表示读取的字节数目 |
void close() | 关闭此输入流并释放与该流关联的所有系统资源 |
OutputStream的常用方法
方法声明 | 功能描述 |
---|---|
void write() | 向输出流写入一个字节 |
void write(byte[] b) | 把参数b指定的字节数组的所有字节写道输出流 |
void write(byte[] b,int off,int len) | 将指定byte数组中从偏移量off开始的len个字节写入输出流 |
void flush() | 刷新此输入流并强制写出所有缓冲的输出字节 |
void close() | 关闭此输出流并释放与此流相关的所有系统资源 |
FileInputStream和FileOutputStream
针对文件的读写,JDK专门提供了两个类,FileInputStream和FileOutputStream。
先在当前文件创建一个写有“itcast”的“t.txt”文件。
import java.io.*;
public class Test{
public static void main(String[] args) throws Exception{
//创建一个文件字节输入流
FileInputStream in = new FileInputStream("t.txt");
int b = 0;
while (true){
b = in.read(); //变量b记住读取的一个字节
if (b == -1){ //如果读取的字节为-1,跳出循环
break;
}
System.out.println(b);
}
in.close();
}
}
运行结果:
105
116
99
97
115
116
如果指定的文件不存在,就会先创建文件,再写入数据;如果文件存在,则会先清空文件内容再进行写入。
import java.io.*;
public class Test{
public static void main(String[] args) throws Exception{
//创建一个文件字节输出流
FileOutputStream out = new FileOutputStream("example.txt");
String s = "好好学习";
out.write(s.getBytes(StandardCharsets.UTF_8));
out.close();
}
}
运行结果:当前目录会生成一个内容为“好好学习”的example.txt文件。
若想在存在的文件内容后追加新内容,可使用构造函数FileOutputStream(String fileName,boolean append)
来创建文件输出流对象,把append参数设为true。
import java.io.*;
public class Test{
public static void main(String[] args) throws Exception{
//创建一个文件字节输出流
FileOutputStream out = new FileOutputStream("example.txt",true);
String str = "天天向上";
byte[] b = str.getBytes();
for (int i=0;i<b.length;i++){
out.write(b[i]);
}
out.close();
}
}
运行结果:在原文件内容中加入了“天天向上”。
IO流在进行数据读写操作时会出现异常,为了代码整洁,使用throws关键字将异常抛出。然而一旦遇到异常,IO流的close()方法无法得到执行,所以,为了close()方法能够执行,通常将关闭流的操作写在finally代码块中:
finally{
try{
if(in!=null) //如果in不为空,关闭输入流
in.close();
}catch (Exception e){
e.printStackTrace();
}
}
finally{
try{
if(out!=null) //如果out不为空,关闭输出流
out.close();
}catch (Exception e){
e.printStackTrace();
}
}
文件的拷贝
import java.io.*;
public class Test{
public static void main(String[] args) throws Exception{
//创建一个字节输入流,用于读取当前目录下source文件中的wav文件
FileInputStream in = new FileInputStream("source/BGM.wav");
//创建一个字节输出流,用于将读取的数据写入target目录下的文件中
FileOutputStream out = new FileOutputStream("target/BGM.wav");
int b; //定义一个int类型的变量,记住每次读取的一个字节
long begintime = System.currentTimeMillis();//获取拷贝前系统时间
while((b=in.read())!=-1){ //读取一个字节并判断是否读到文件末尾
out.write(b); //将读到的字节写入文件
}
long endtime = System.currentTimeMillis();//获取拷贝后系统时间
System.out.println("拷贝文件所消耗时间:"+(endtime-begintime)+"毫秒");
in.close();
out.close();
}
}
运行结果:
拷贝文件所消耗时间:29202毫秒
注:定义文件路径在Windows中的目录符号是反斜线\
,但反斜线在Java中是特殊字符,表转义符,所以用\\
,也可以用正斜线/
来表示。
字节流的缓冲区
由于一个字节的读取使得操作文件效率低下,所以可以定义一个字节数组作为缓冲区。(通俗的讲,就是由一个一个搬变成了一车一车拉)
import java.io.*;
public class Test{
public static void main(String[] args) throws Exception{
//创建一个字节输入流,用于读取当前目录下source文件中的wav文件
FileInputStream in = new FileInputStream("source\\BGM.wav");
//创建一个字节输出流,用于将读取的数据写入target目录下的文件中
FileOutputStream out = new FileOutputStream("target\\BGM.wav");
byte[] buff = new byte[1204]; //定义一个字节数组作为缓冲区
int len; //定义一个int类型的变量,记住读入缓冲区的字节数
long begintime = System.currentTimeMillis();//获取拷贝前系统时间
while((len=in.read(buff))!=-1){ //读取一个字节并判断是否读到文件末尾
out.write(buff,0,len); //从第一个字节开始,向文件写入len个字节
}
long endtime = System.currentTimeMillis();//获取拷贝后系统时间
System.out.println("拷贝文件所消耗时间:"+(endtime-begintime)+"毫秒");
in.close();
out.close();
}
}
运行结果:
拷贝文件所消耗时间:34毫秒
可以看出消耗时间明显减少。程序中的缓冲区就是一块内存,用于存放暂时输入输出的数据,减少了对文件的操作次数,提高了读写数据的效率。
字节缓冲流
BufferedInputStream和BufferedOutputStream
在IO包中提供了两个带缓冲的字节流BufferedInputStream和BufferedOutputStream,这两个流都使用了装饰设计模式。它们的构造方法中分别接收InputStream和OutputStream类型的参数作为包装对象,在读写数据时提供缓冲功能。
import java.io.*;
public class Test{
public static void main(String[] args) throws Exception{
//创建一个带缓冲区的输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("source/BGM.wav"));
//创建一个带缓冲区的输出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("target/BGM.wav"));
int b;
long begintime = System.currentTimeMillis();
while ((b=bis.read())!=-1){
bos.write(b);
}
long endtime = System.currentTimeMillis();
System.out.println("拷贝文件所消耗时间:"+(endtime-begintime)+"毫秒");
bis.close();
bos.close();
}
}
运行结果:
拷贝文件所消耗时间:78毫秒
创建了BufferedInputStream和BufferedOutputStream两个缓冲流对象,两个流内部都定义了大小为8192的字节数组。
字符流
Reader输出流和Writer输入流
字符流也有两个抽象的顶级父类,分别是Reader和Writer。Reader是字符输入流,用于从某个原设备读取字符,Writer是字符输出流,用于向某个目标设备写入字符。
FileReader和FileWriter
字符流操作文件有字符输入流FileReader和字符输出流FileWriter。
字符流的read()方法返回的是int类型的值,想获得字符就得强制类型转换。
import java.io.*;
public class Test{
public static void main(String[] args) throws Exception{
//创建一个FileReader对象用来读取文件中的字符
FileReader reader = new FileReader("t.txt");
int ch; //定义一个变量用于记录读取的字符
while((ch=reader.read())!=-1){ //循环判断是否读取到文件的末尾
System.out.println((char)ch);
}
reader.close();
}
}
运行结果:
i
t
c
a
s
t
下面是写入文件,如果指定的文件不存在,就会先创建文件,再写入数据;如果文件存在,则会先清空文件内容再进行写入。
import java.io.*;
public class Test{
public static void main(String[] args) throws Exception{
//创建一个FileWriter对象用于向文件中写入数据
FileWriter writer = new FileWriter("example.txt");
String str = "好好学习,天天向上";
writer.write(str); //将字符串写入到文本文件中
writer.write("\r\n"); //将输出语句换行
writer.close();
}
}
同样可以通过调用重载的构造方法在文件末尾追加数据:FileWriter writer = new FileWriter("example.txt",true);
。
字符缓冲流
BufferedReader和BufferedWriter
字符流同样提供了带缓冲区的包装流,分别是BufferedReader和BufferedWriter,需要注意的是在BufferedReader中有一个重要的方法readLine()
,用于一次读取一行文本。
import java.io.*;
public class Test{
public static void main(String[] args) throws Exception{
FileReader reader = new FileReader("src.txt");
FileWriter writer = new FileWriter("des.txt");
//创建一个BufferedReader缓冲对象
BufferedReader br = new BufferedReader(reader);
//创建一个BufferedWriter缓冲对象
BufferedWriter bw = new BufferedWriter(writer);
String str;
while ((str=br.readLine())!=null){ //每次读取一行文本,判断是否到文件末尾
bw.write(str);
bw.newLine(); //写入一个换行符,该方法会根据不同的操作系统生成相应的换行符
}
br.close();
bw.close();
}
}
注:当缓冲区写满或调用close()方法时,缓冲区中的字符才会被写入到目标文件,因此一定要调用close()方法。
LineNumberReader
是可以追踪行号的输入流,是BufferedReader的直接子类。
import java.io.*;
public class Test{
public static void main(String[] args) throws Exception{
//创建字符输入流
FileReader fr = new FileReader("src/Loop.java");
//创建字符输出流
FileWriter fw = new FileWriter("copy.java");
//包装
LineNumberReader lr = new LineNumberReader(fr);
lr.setLineNumber(0); //设置读取文件的起始行号为0
String line = null;
while ((line=lr.readLine())!=null){
//将行号写入到文件中
fw.write(lr.getLineNumber()+":"+line);
fw.write("\r\n"); //写入换行
}
lr.close();
fw.close();
}
}
从运行结果可以看出,行号是从1开始的,因为LineNumberReader类在读取换行符、回车符或者回车后紧跟换行符时,行号自动加1。
转换流
JDK提供了两个类可以将字节流转换成字符流,InputStreamReader和OutoutStreamWriter分别是Reader和Writer的子类。
import java.io.*;
public class Test{
public static void main(String[] args) throws Exception{
//创建字节输入流
FileInputStream in = new FileInputStream("src.txt");
//将字节流输入转换成字符流输入
InputStreamReader isr = new InputStreamReader(in);
//对字符流对象进行包装
BufferedReader br = new BufferedReader(isr);
//创建字节输出流
FileOutputStream out = new FileOutputStream("des.txt");
//将字节输出流转换成字符输出流
OutputStreamWriter osw = new OutputStreamWriter(out);
//对字符输出流对象进行包装
BufferedWriter bw = new BufferedWriter(osw);
String line;
while ((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
}
br.close();
bw.close();
}
}
注:只针对操作文本文件的字节流进行转换,如果字节流操作操作的是一张图片,会造成数据丢失。
其他IO流
ObjectInputStream和ObjectOutputStream
程序运行时,会在内存中创建多个对象,程序结束后这些对象都会被当作垃圾回收。如果想永久保存这些对象,可以将对象转为字节数据写入到硬盘上,这个过程称为对象序列化。ObjectOutputStream(对象输出流)来实现序列化。
注:当对象序列化时,必须保证该对象实现Serializable接口,否则会异常。
import java.io.*;
public class Test{
public static void main(String[] args) throws Exception{
Person p = new Person("Payne","xiaochen",24);
System.out.println("-----写入文件前-----");
System.out.println("Person对象id:"+p.getId());
System.out.println("Person对象name:"+p.getName());
System.out.println("Person对象age:"+p.getAge());
//创建文件输出流对象,将数据写入objectStream.txt文件中
FileOutputStream fos = new FileOutputStream("objectStream.txt");
//创建对象输出流对象,用于处理输出流对象写入的数据
ObjectOutputStream oos = new ObjectOutputStream(fos);
//将Person对象输出到输出流中
oos.writeObject(p);
}
}
class Person implements Serializable {
private String id;
private String name;
private int age;
public Person(String id,String name,int age){
super();
this.id = id;
this.name = name;
this.age = age;
}
public String getId(){
return id;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
}
运行结果:
-----写入文件前-----
Person对象id:Payne
Person对象name:xiaochen
Person对象age:24
Person对象被序列化后会生成二进制数据保存在“objectStream.txt”文件中,通过这些二进制数据可以恢复序列化之前的Java对象,此过程称为反序列化。ObjectInputStream类(对象输入流),可以实现对象的反序列化。
import java.io.*;
public class Test{
public static void main(String[] args) throws Exception{
//创建文件输入流对象,用于读取指定文件的数据
FileInputStream fis = new FileInputStream("objectStream.txt");
//创建对象输入流对象,并且从指定的输入流中读取数据
ObjectInputStream ois = new ObjectInputStream(fis);
//从objectStream.txt中读取Person对象
Person p = (Person) ois.readObject();
System.out.println("-----从文件中读取后-----");
System.out.println("Person对象id:"+p.getId());
System.out.println("Person对象name:"+p.getName());
System.out.println("Person对象age:"+p.getAge());
}
}
class Person implements Serializable {
private String id;
private String name;
private int age;
public Person(String id,String name,int age){
super();
this.id = id;
this.name = name;
this.age = age;
}
public String getId(){
return id;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
}
运行结果:
-----从文件中读取后-----
Person对象id:Payne
Person对象name:xiaochen
Person对象age:24
DataInputStream和DataOutputStream
当不需要存储整个对象的信息,而只需要存储对象的成员数据的基本数据类型时,可以使用DataInputStream和DataOutputStream。
可以用writeUTF()方法向输出流中写入采用UTF-8字符编码的字符串,用readUTF()方法从输入流中读取UTF-8字符编码的字符串。
import java.io.*;
public class Test{
public static void main(String[] args) throws Exception{
FileOutputStream fos = new FileOutputStream("C:/Users/13403/Desktop/dataStream.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos); //字节缓冲流
DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(12); //写一个字节
dos.writeChar('1'); //写一个字符
dos.writeBoolean(true); //写一个布尔值
dos.writeUTF("同学,你好"); //写一个转换成UTF-8的字符串
dos.close();
FileInputStream fis = new FileInputStream("C:/Users/13403/Desktop/dataStream.txt");
BufferedInputStream bis = new BufferedInputStream(fis); //字节缓冲流
DataInputStream dis = new DataInputStream(bis);
System.out.println(dis.readByte()); //读一个字节
System.out.println(dis.readChar()); //读一个字符
System.out.println(dis.readBoolean()); //读一个布尔值
System.out.println(dis.readUTF()); //读一个转换成UTF-8的字符串
dis.close();
}
}
运行结果:
12
1
true
同学,你好
注:只有读取数据的顺序和写数据的顺序一样才能保证准确性。
PrintStream打印流
之前通过write()方法只能输出字节或者字符类型数据,输出int类型或者对象等时,得先转为字符串在输出。为了方便操作可以使用PrintStream类用于打印数据的print()和println()方法,称为打印流。
PrintStream可以实现将基本数据类型的数据或者引用数据类型的对象格式化成字符串后再输出。
import java.io.*;
public class Test{
public static void main(String[] args) throws Exception{
//创建一个PrintStream对象,将FileOutputStream读取到的数据输出
PrintStream ps = new PrintStream(new FileOutputStream("printStream.txt",true));
Student stu = new Student();
ps.print("这是一个数字:");
ps.println(19);
ps.println(stu); //打印Student对象
}
}
class Student{
//重写Object的toString()方法
public String toString(){
return "你好,同学";
}
}
标准输入输出流
再System类中定义了三个常量:in和out、err。in为InputStream类型,标准输入流,默认情况下读取键盘输入的数据,out为PrintStream类型,标准输出流,默认情况下将数据输出到命令行窗口,err为PrintStream类型,标准错误流,和out一样将数据输出到控制台,但输出的的程序运行时的错误信息。
public class Test{
public static void main(String[] args) throws Exception{
StringBuffer sb = new StringBuffer();
int ch;
//while用于读取键盘输入的数据
System.out.print("输入:");
while((ch=System.in.read())!=-1){
if(ch=='\r'||ch=='\n'){ //对字符进行判断,如果是回车或换行,跳出循环
break;
}
sb.append((char)ch);
}
System.out.print("输出:"+sb);
}
}
运行结果:
输入:123abcd
输出:123abcd
可以对标准输入流和输出流进行重定向。
重定向流常用的静态方法
方法声明 | 功能描述 |
---|---|
void setIn(InputStream in) | 对标准输入流重定向 |
void setOut(PrintStream out) | 对标准输出流重定向 |
void Err(PrintStream out) | 对标准错误流输出重定向 |
下面利用标准输入输出流重定向拷贝文件。
import java.io.*;
public class Test{
public static void main(String[] args) throws Exception{
System.setIn(new FileInputStream("source.txt")); //对输入流进程重定向
System.setOut(new PrintStream("target.txt")); //对输出流进程重定向
//使用转换流将标准输出流转换为字符流,再用BufferedReader包装流包装
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line;
while((line=br.readLine())!=null){
System.out.println(line);
}
}
}
PipedInputStream和PipedOutputStream
分别为管道输入流和管道输出流,是一种比较特殊的流,必须先建立连接才能彼此间通信。PipedOutputStream用于向管道写入数据,PipedInputStream用于从管道读取写入的数据。可以完成线程间的通信。
import java.io.*;
public class Test{
public static void main(String[] args) throws Exception{
final PipedInputStream pis = new PipedInputStream(); //创建PipedInputStream对象
final PipedOutputStream pos = new PipedOutputStream(); //创建PipedOutputStream对象
//二者建立连接,也可以写成pos.connect(pis)
pis.connect(pos);
//创建一个线程,这里用了匿名内部实现类
new Thread(new Runnable() {
public void run() {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));//将转换流进行包装
//将从键盘读取的数据写入管道流
PrintStream ps = new PrintStream(pos);
while(true){
try{
System.out.print(Thread.currentThread().getName()+"要求输入内容:");
ps.println(br.readLine());//将读取的一行转换成字符串打印
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
}
}
},"发送数据的线程").start();
//创建一个线程
new Thread(new Runnable() {
public void run() {
//下面代码是从管道流中读出数据,每读一行数据输出一次
BufferedReader br = new BufferedReader(new InputStreamReader(pis));
while(true){
try{
System.out.println(Thread.currentThread().getName()+"收到的内容:"+br.readLine());
}catch (Exception e){
e.printStackTrace();
}
}
}
},"接收数据的线程").start();
}
}
运行结果:
发送数据的线程要求输入内容:你好呀
接收数据的线程收到的内容:你好呀
发送数据的线程要求输入内容:Hello
接收数据的线程收到的内容:Hello
发送数据的线程要求输入内容:
可以看到两个对象通过connect()方法建立管道连接后,开启两个线程,一个用于将键盘输入的数据写入管道输出流,一个用于从管道中读取写入的数据,完成线程间的通信。
在字符流中也有一对PipedReader和PipedReader用于管道的通信,用法相似。
ByteArrayInputStream和ByteArrayOutputStream
之前的都是将文件直接存储到硬盘,JDK中提供了一个ByteArrayOutputStream类,在创建对象时就创建一个byte型数组的缓冲区,会把所有数据写入缓冲区,最后一次性写入文件。
import java.io.*;
public class Test{
public static void main(String[] args) throws Exception{
FileInputStream fis = new FileInputStream("source.txt");
ByteArrayOutputStream bos = new ByteArrayOutputStream(); //创建一个字节数组缓冲区
FileOutputStream fos = new FileOutputStream("target.txt");
//下面的代码是循环读取缓冲区中的数据,并将数据一次性写入文件
int b;
while((b=fis.read())!=-1){
bos.write(b); //数据写入缓冲区
}
fis.close();
bos.close();
fos.write(bos.toByteArray()); //将缓冲区中的数据一次性写入文件
fos.close();
}
}
注:缓冲区会根据存入数据的多少而自动变化,但读取的文件非常大时,就不能使用这个类,否则会造成内存溢出。
ByteInputStream是读取缓冲区中的数据,通过构造方法ByteArrayInputStream(byte[] b)
,从字节数组中每次读取一个字节。
import java.io.*;
public class Test{
public static void main(String[] args) throws Exception{
byte[] bt = new byte[]{97,98,99,100}; //创建一个字节数组
ByteArrayInputStream bis = new ByteArrayInputStream(bt); //读取字节数组中的数据
//下面的代码是循环读取缓冲区中的数据
int b;
while ((b=bis.read())!=-1){
System.out.println((char)b);
}
}
}
运行结果:
a
b
c
d
再举一个例子,将source.txt文本中的数据写入缓冲区再读取。
import java.io.*;
public class Test{
public static void main(String[] args) throws Exception{
FileInputStream fis = new FileInputStream("source.txt");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int b;
while((b=fis.read())!=-1){
bos.write(b); //数据写入缓冲区
}
fis.close();
bos.close();
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); //读取缓冲区数组中的数据
//下面的代码是循环读取缓冲区中的数据
int c;
while ((c=bis.read())!=-1){
System.out.print((char)c);
}
}
}
运行结果:
www
456
xyz
CharArrayReader和CharArrayWriter
import java.io.*;
public class Test{
public static void main(String[] args) throws Exception{
FileReader fr = new FileReader("source.txt");
CharArrayWriter cw = new CharArrayWriter(); //在内存中创建一个字符数组缓冲区
//下面的代码是将数据写入缓冲区
int b;
while ((b=fr.read())!=-1){
cw.write(b);
}
fr.close();
cw.close();
char[] c = cw.toCharArray(); //将缓冲区中的数组转换成字符型数组
CharArrayReader cr = new CharArrayReader(c); //读取字符数组中的数据
//下面的代码时从缓冲区中读取数据并打印
int i;
while ((i=cr.read())!=-1){
System.out.print((char)i);
}
}
}
运行结果:
www
456
你好
SequenceInputStream
之前对文件进行操作都是通过一个流对数据进行处理。SequenceInputStream类可以将几个输出流串联在一起,合并为一个输出流。例如在下载文件时,可以分段下载最后再合并。
import java.io.*;
public class Test{
public static void main(String[] args) throws Exception{
//下面的代码是创建了两个流对象in1、in2
FileInputStream in1 = new FileInputStream("stream1.txt");
FileInputStream in2 = new FileInputStream("stream2.txt");
//创建一个序列流,合并两个字节流in1和in2
SequenceInputStream sis = new SequenceInputStream(in1,in2);
FileOutputStream out = new FileOutputStream("stream.txt");
int len;
byte[] b = new byte[1024]; //创建一个1024个字节数组作为缓冲区
//下面代码用于循环读取三个流中的文件
while ((len=sis.read(b))!=-1){
out.write(b,0,len); //将缓冲区的数据输出
out.write("\r\n".getBytes()); //换行
}
sis.close();
out.close();
}
}
运行结果:
在创建SequenceInputStream对象时使用的构造方法只有两个参数,若想合并更多流,需要接收一个Enumeration类型的对象。
import java.io.*;
import java.util.*;
public class Test{
public static void main(String[] args) throws Exception{
Vector vector = new Vector(); //创建Vector对象
//下面的代码是创建了三个输入流对象in1、in2、in3
FileInputStream in1 = new FileInputStream("stream1.txt");
FileInputStream in2 = new FileInputStream("stream2.txt");
FileInputStream in3 = new FileInputStream("stream3.txt");
//下面代码是向Vector中添加三个输入流对象
vector.addElement(in1);
vector.addElement(in2);
vector.addElement(in3);
Enumeration e = vector.elements(); //获取Vector对象中的元素
//将Enumeration对象中的流合并
SequenceInputStream sis = new SequenceInputStream(e);
FileOutputStream out = new FileOutputStream("stream.txt");
int len;
byte[] b = new byte[1024]; //创建一个大小为1024个字节数组的缓冲区
while ((len=sis.read(b))!=-1){
out.write(b,0,len);
}
sis.close();
out.close();
}
}