Java IO流层次结构.docx
《Java IO流层次结构.docx》由会员分享,可在线阅读,更多相关《Java IO流层次结构.docx(11页珍藏版)》请在冰豆网上搜索。
JavaIO流层次结构
JavaI/O流层次结构
2007-08-1816:
16
一、I/O流层次
图7.1.1是对java.io包中的字节流关系的描述。
对于字符流。
我们将在7.4节中介绍。
我们通过图7.1.1可以看到io处理的类层次。
所有的输入流都是InputStream继承而来的。
在类InputStream中定义的方法包括从流中读取数据,在流中标记某个位置获取流中可得到的数据量,以及重置流中的读取位置等。
同样,所有的输出流都是从抽象类OutputStream继承而来的。
在类OutputStream中定义的方法包括向流中写人数据以及刷空流等。
其他的输入/出流作为IntputStream和OutputStream的子类,主要实现对特定流的输入和输出处理。
图7.1.1I/O处理的类层次
注:
图中,细线框中的内容为类,粗线框中的内容为接口。
线段表示继承,射线表示接口的实现。
FileInputStram和FileOutputStram用于读/写本地文件系统中的文件。
PipedInputStream和PipedOutputStream用来实现管逍的输入出。
ByteArrayInputkStream和ByteArrayOutputStream用于读/写内存数据。
StringBufferInputStream使程序可以从一个StringBuffer类的可变字符串中读取数据。
SequenceInputStream用来把多输入流连接到一个输出流。
FilterInputStream和FilterOutputStream分别重写了类Input
Stream和OutputStream中的所有方法,为过滤流提供了统一的接口,使得在读写数据的同时可以对数据进行处理。
DateInputStream和DataOutPutstream可以用与机器无关的格式读/写Java的基本数据类型。
BufferedInputStream和BufferedOutputStream在读/写的同时对数据进行缓存,从而减少对数据源的访问,提高运行效率。
ObjectInputStream和ObjectOutputStream用来直接进行对象的读写。
LineNumberInputStream可以在读取数据的同时记录读取的行数。
PushbackInputStream包括一个单字节的缓冲区,使得在读取数据时可以预取下一个字符。
PrintStream中提供了方便的输出方法。
除了上面所说的流以外,包java.io中还提供了其他的一些类和接口。
类File和FileDescriptor用于描述本地文件系统中的文件成目录。
类RandomAccessFile用于描述一个随机访问文件。
类StreamTokenizer把流中的内容分解为记号(Token),通常用于文本文件的解析。
一个共实现接口DataInput和DataOutput中定义的方法后,就可以用与机器无关的格式读/写Java的基本类型数据。
类DateInput
Stream、DataOutputStream和RandomAccessFile分别实现了这两个接口。
接口ObjectInput和ObjectOutput中提供了一组方法,支持对对象的直接读/写。
类ObjectInputStream和ObjectOutputStream分别实现了这两个接口。
接口FilenameFilter主要用于实现文件名查找模式的匹配。
二、InputStream和OutputStream
抽象类InputStream和OutputStream是所有流的基类,它们分别提供了输入和输出处理的基本接口,并且都分地实现了其中的某些方法。
由于InputStream和OutputStream都是抽象类,所以不能直接生成它们的对象。
我们来看一下InputStream和OutputStream中所封装的主要内容,以对输对出处理的框架有一个了解。
1.InputStream
除了构造方法外,InputStream中所提供的方法主要有:
(1)从流中读取数据
intread();
从输入流中读取了一个字节,返回范围在0到255之间的一个整数,该方法的属性为abstract,必须为子类所实现。
intread(byteb[]);
从输入流中读取长度为b.length的数据,写入字节数组b,并返回读取的字节数。
intread(byteb[],intoff,intlen);
从输入流中读取长度为len的数据,写入字节数组b中从索引off开始的位置,并返回读取的字节数。
对于以上方法,如果达到流的末尾位置,刚返回-1表明流的结束。
intavailable();
返回从输入流中可以读取的字节数。
longskip(longn);
输入流的当前读取位置向前移动n字节,并返回实际跳过的字节数。
(2)关闭流并且释放与该流相关的系统资源
close();
关闭流可以通过调用方法close()显式进行,也可以由运行时系统在则流对象进行垃圾收集时隐式进行。
(3)使用输入流中的标记
voidmark(intreadlimit);
在输入流的当前读取位置作标记。
从该位置开始读取readlimit所指定的数据后,标记失效。
voidreset();
重置输入流的读取位置为方法mark()所标记的位置。
BooleanmarkSuppont();
确定输入流是否支持方法mark()和reset()。
从以上方法中可以看到,InputStream中主要提供了对数据该取的基本支持,其中的方法通常都需要在于类中被重写,以提高效率或是适合于特定流的需要。
2.OutputStream
除了构造方法外,OutputStream中封装的方法主要实现对输出数据的支持。
(1)输出数据
voidwrite(intb);
将指定的字节b写入输出流。
该方法的属性为abstract,必须为子类所实现。
注意:
参数中的b为int类型,如果b的值大于255,则只输出它的低位字节所表示的值。
voidwrite(byteb[]);
把字节数组b中的b.length个字节写入输出流。
voidwrite(byteb[],intoff,intlen);
把字节数组b中从索引off开始的len个字节写入输出流。
(2)flush()
刷空输出流,并输出所有被缓存的字节。
(3)关闭流
与类InputStream类似,可以用方法close()显式地关闭输出流,也可以由运行时系统在对流对象进行垃圾收集时隐式关闭输出流。
通常OutputStream中的方法需在于类中被重写,以提高效率或是适合于特定流的需要。
Java数据流2(PipedInputStream,PipedOutputStream...)
2007-08-1817:
30
字节流的高级应用
?
管道流
管道用来把一个程序、线程和代码块的输出连接到另一个程序、线程和代码块的输入。
java.io中提供了类PipedInputStream和PipedOutputStream作为管道的输入/输出流
管道输入流作为一个通信管道的接收端,管道输出流则作为发送端。
管道流必须是输入输出并用,即在使用管道前,两者必须进行连接
管道输入/输出流可以用两种方式进行连接:
– 在构造方法中进行连接
?
PipedInputStream(PipedOutputStreampos);
?
PipedOutputStream(PipedInputStreampis);
– 通过各自的connect()方法连接
?
在类PipedInputStream中,connect(PipedOutputStreampos);
?
在类PipedOutputStream中,connect(PipedInputStreampis);
PipedStream示例:
1.新建工程pipedstreamtest,在工程中建Sender.java,Receiver.java,PipedStreamTest.java文件
2.各Java文件代码如下:
2.1Sender.java
packagepipedstreamtest;
importjava.io.*;
publicclassSenderextendsThread{
privatePipedOutputStreamout=new PipedOutputStream();
publicPipedOutputStreamgetOutputStream(){
returnout;
}
publicSender(){
}
publicvoidrun(){
StringstrInfo=newString("hello,receiver!
");
try{
out.write(strInfo.getBytes());
out.close();
}
catch(Exceptione){
e.printStackTrace();
}
}
}
2.2 Receiver.java
packagepipedstreamtest;
importjava.io.*;
publicclassReceiverextendsThread{
privatePipedInputStreamin=newPipedInputStream();
publicPipedInputStreamgetInputStream(){
returnin;
}
publicvoidrun(){
StringstrInfo=newString("hello,receiver!
");
byte[]buf=newbyte[1024];
try{
intlen=in.read(buf);
System.out.println("thefollowingmessageforsender:
\n"+
newString(buf,0,len));
in.close();
}
catch(Exceptione){
e.printStackTrace();
}
}
publicReceiver(){
}
}
2.3PipedStream.java
packagepipedstreamtest;
importjava.io.*;
publicclassPipedStreamTest{
publicstaticvoidmain(String[]args)throwsException{
Sendert1=newSender();
Receivert2=newReceiver();
PipedOutputStreamout=t1.getOutputStream();
PipedInputStreamin=t2.getInputStream();
out.connect(in);
t1.start();
t2.start();
}
}
例8.8管道流。
本例例管道流的使用方法。
设输入管道in与输出管道out已连接,Send线程向输出管道out发送数据,Receive线程从输入管道in中接收数据。
程序如下:
importjava.io.*;
publicclassPipedstream
{
publicstaticvoidmain(Stringargs[])
{
PipedInputStreamin=newPipedInputStream();
PipedOutputStreamout=newPipedOutputStream();
try
{
in.connect(out);
}
catch(IOExceptionioe){}
Sends1=newSend(out,1);
Sends2=newSend(out,2);
Receiver1=newReceive(in);
Receiver2=newReceive(in);
s1.start();
s2.start();
r1.start();
r2.start();
}
}
classSendextendsThread//发送线程
{
PipedOutputStreamout;
staticintcount=0;//记录线程个数
intk=0;
publicSend(PipedOutputStreamout,intk)
{
this.out=out;
this.k=k;
this.count++;//线程个数加1
}
publicvoidrun()
{
System.out.print("\r\nSend"+this.k+":
"+this.getName()+"");
inti=k;
try
{
while(i<10)
{
out.write(i);
i+=2;
sleep
(1);
}
if(Send.count==1)//只剩一个线程时
{
out.close();//关闭输入管道流
System.out.println("outclosed!
");
}
else
this.count--;//线程个数减1
}
catch(InterruptedExceptione){}
catch(IOExceptione){}
}
}
classReceiveextendsThread//接收线程
{
PipedInputStreamin;
publicReceive(PipedInputStreamin)
{
this.in=in;
}
publicvoidrun()
{
System.out.print("\r\nReceive:
"+this.getName()+"");
try
{
inti=in.read();
while(i!
=-1)//输入流未结束时
{
System.out.print(i+"");
i=in.read();
sleep
(1);
}
in.close();//关闭输入管道流
}
catch(InterruptedExceptione){}
catch(IOExceptione)
{
System.out.println(e);
}
}
}
程序运行结果如下:
Send1:
Thread-0
Send2:
Thread-1
Receive:
Thread-21
Receive:
Thread-323457outclosed!
689java.io.IOException:
Pipeclosed!
?
数据流
DataInputStream和DataOutputStream
?
在提供了字节流的读写手段的同时,
?
以统一的通用的形式向输入流中写入boolean,int,long,double等基本数据类型,并可以在次把基本数据类型的值读取回来。
?
提供了字符串读写的手段。
?
分别实现了DataInput和DataOutput接口
声明类:
PublicclassDataInputStreamextendsfilterInputStreamimplementsDataInput
例8.9数据流。
本例演示数据流的使用方法。
程序如下:
importjava.io.*;
publicclassDatastream
{
publicstaticvoidmain(Stringarg[])
{
Stringfname="student1.dat";
newStudent1("Wang").save(fname);
newStudent1("Li").save(fname);
Student1.display(fname);
}
}
classStudent1
{
staticintcount=0;
intnumber=1;
Stringname;
Student1(Stringn1)
{
this.count++;//编号自动加1
this.number=this.count;
this.name=n1;
}
Student1()
{
this("");
}
voidsave(Stringfname)
{
try
{//添加方式创建文件输出流
FileOutputStreamfout=newFileOutputStream(fname,true);
DataOutputStreamdout=newDataOutputStream(fout);
dout.writeInt(this.number);
dout.writeChars(this.name+"\n");
dout.close();
}
catch(IOExceptionioe){}
}
staticvoiddisplay(Stringfname)
{
try
{
FileInputStreamfin=newFileInputStream(fname);
DataInputStreamdin=newDataInputStream(fin);
inti=din.readInt();
while(i!
=-1)//输入流未结束时
{
System.out.print(i+"");
charch;
while((ch=din.readChar())!
='\n')//字符串未结束时
System.out.print(ch);
System.out.println();
i=din.readInt();
}
din.close();
}
catch(IOExceptionioe){}
}
}
程序运行结果如下:
1Wang
2Li
?
对象流
?
对象的持续性(Persistence)
– 能够纪录自己的状态一边将来再生的能力,叫对象的持续性
?
对象的串行化(Serialization)
– 对象通过写出描述自己状态的的数值来记录自己的过程叫串行化。
串行化的主要任务是写出对象实例变量的数值,如果变量是另一个对象的引用,则引用的对象也要串行化。
这个过程是递归的
?
对象流
– 能够输入输出对象的流称为对象流。
– 可以将对象串行化后通过对象输入输出流写入文件或传送到其它地方
在java中,允许可串行化的对象在通过对象流进行传输。
只有实现Serializable接口的类才能被串行化,Serializable接口中没有任何方法,当一个类声明实现Serializable接口时,只是表明该类加入对象串行化协议
要串行化一个对象,必须与一定的对象输出/输入流联系起来,通过对象输出流将对象状态保存下来(将对象保存到文件中,或者通过网络传送到其他地方),再通过对象输入流将对象状态恢复
类ObjectOutputStream和ObjectInputStream分别继承了接口ObjectOutput和ObjectInput,将数据流功能扩展到可以读写对象,前者用writeObject()方法可以直接将对象保存到输出流中,而后者用readObject()方法可以直接从输入流中读取一个对象
例8.10对象流。
本例声明Student2为序列化的类。
Save方法中,创建对象输出流out,并以添加方式向文件中直接写入当前对象out.writeObject(this);display方法中,创建对象输入流in,从文件中直接读取一个对象in.readObject(),获得该对象的类名、接口名等属性,并显示其中的成员变量。
程序如下:
importjava.io.*;
publicclassStudent2implementsSerializable//序列化
{
intnumber=1;
Stringname;
Student2(intnumber,Stringn1)
{
this.number=number;
this.name=n1;
}
Student2()
{
this(0,"");
}
voidsave(Stringfname)
{
try
{
FileOutputStreamfout=newFileOutputStream(fname);
ObjectOutputStreamout=newObjectOutputStream(fout);
out.writeObject(this);//写入对象
out.close();
}
catch(FileNotFoundExceptionfe){}
catch(IOExceptionioe){}
}
voiddisplay(Stringfname)
{
try
{
FileInputStreamfin=newFileInputStream(fname);
ObjectInputStreamin=newObjectInputStream(fin);
Student2u1=(Student2)in.readObject();//读取对象
System.out.println(u1.getClass().getName()+""+
u1.getClass().getInterfaces()[0]);
System.out.println(""+u1.number+""+u1.name);
in.close();
}
catch(FileNotFoundExceptionfe){}
catch(IOExceptionio