Java I/O系统
编程语言I/O系统常使用流这个抽象的概念,它代表任何有能力产生数据的数据源对象或者任何有能力的数据接收端对象。“流”屏蔽了实际I/O设备中处理数据的细节。
Java类库的I/O类分为输入和输出两部分,通过继承,任何自InputStream派生出来的类都具有命名为read()的基本方法,用于读取单个字节或者字节数组。同样,任何自OutputStream派生出来的类都具有命名为write()的基本方法,用于读取单个字节或者字节数组。但是我们通常不会去使用它们,它们之所以会存在是因为别的类可以使用它们,以便提供更有用的接口。
1,InputStream
InputStream用来表示那些从不同数据源产生输入的类。
1)字节数组。
2)String对象
3)文件
4)管道
5)其它数据源。
每一种数据源都有相应的InputStream子类。
2,OutputStream
该类别的类决定了输出所要去往的目标:字节数组,文件或者管道。
3,FilterInputStream和FilterOutputStream
FilterInputStream和FilterOutputStream是用来提供装饰器接口以控制特定输入流和输出流的两个类。
1)FilterInputStream
FilterInputStream类能完成两种完全不同的事情。其中,DataInputStream允许我们读取不同类型数据以及String对象(所有方法都以read开,例如,readByte(),readFloat()等等)。搭配相应的DataInputStream,我们就可以通过数据流将基本类型的数据从一个地方迁移到另一个地方。
2)FilterOutputStream
与DataInputStream对应的是DataOutputStream,它可以将各种基本数据类型以及String对象格式化输出到流中。这样,任何机器上的DataInputStream都能读取它们。所有方法均已write开头,例如,writeFloat(),writeByte()等。
4,RandomAccessFile
RandomAccessFile适用于大小已知纪录组成的文件,所以我们可以使用seek()将纪录从一处转移到另一处,然后读取或者修改记录。它是一个完全独立的类,除了实现DataInput和DataOutput接口(DataInputStream和DataOutputStream也实现了这两个接口)之外,它和这两个继承层次没有任何关联。只有RandomAccessFile支持搜寻方法,并且只适用于文件。
<span style="font-size:18px;">import java.io.*;
public class UsingRandomAccessFile{
static String file="rTest.dat";
static void display() throws IOException{
RandomAccessFile rf=new RandomAccessFile(file,"r");
for(int i=0;i<7;i++)
System.out.println("Value "+i+":"+rf.readDouble());
System.out.println(rf.readUTF());
rf.close();
}
public static void main(String[] args) throws IOException{
RandomAccessFile rf=new RandomAccessFile(file,"rw");
for(int i=0;i<7;i++)
rf.writeDouble(1.414*i);
rf.writeUTF("This is the end of the file");
rf.close();
display();
rf=new RandomAccessFile(file,"rw");
rf.seek(5*8);
rf.writeDouble(60.000000001);
rf.close();
display();
}
}
</span>
5,新I/O
JDK 1.4的java.nio.*包中引入了新的I/O,其目的在于提高速度。速度的提高来自于所使用的结构更接近于操作系统执行I/O的方式:通道和缓冲区。我们并没有直接和通道交互,我们只是和缓冲区交互,并把缓冲器派送到通道,通道要么从缓冲器获得数据,要么向缓冲区发送数据。
唯一直接与通道交互的缓冲器是ByteBuffer,可以存储未加工字节的缓冲器。它是相当基础的类:通过告知分配多少存储空间来创建一个ByteBuffer对象,并且还有一个方法选择集,用于原始字节形式或基本数据类型输出和读取数据。
<span style="font-size:18px;">import java.io.*;
import java.nio.*;
import java.nio.channels.*;
public class GetChannel{
private static final int SIZE=1024;
public static void main(String[] args) throws Exception{
FileChannel fc=new FileOutputStream("data.txt").getChannel();
fc.write(ByteBuffer.wrap("Some text".getBytes()));
fc.close();
fc=new RandomAccessFile("data.txt","rw").getChannel();
fc.position(fc.size());
fc.write(ByteBuffer.wrap(" Some more".getBytes()));
fc.close();
fc=new FileInputStream("data.txt").getChannel();
ByteBuffer buff=ByteBuffer.allocate(SIZE);
fc.read(buff);
buff.flip();
while(buff.hasRemaining())
System.out.print((char)buff.get());
System.out.println();
}
}
</span>
6,缓冲器细节
Buffer由数据和可以高效访问及操作这些数据的四个索引组成,这4个索引是:mark,position,limit,capacity。
7,对象序列化
Java的对象序列化将那些实现了Serializable的对象转化成一个字节序列,并能够在以后将这个字节序列恢复为原来的对象。这一过程甚至可以通过网络进行:这意味着序列化机制能自动弥补操作系统之间的差异。就其本身来说,对象的序列化是非常有趣的,因为利用它可以实现轻量级持久性。“持久性”意味着一个对象的生成周期并不取决于程序是否正在执行,它可以生存于程序的调用之间。
要序列化一个对象,首先要创建OutputStream对象,然后将其封装在一个ObjectOutputStream对象内。这时,只需要调用writeObject()即可将对象序列化,并将其发送给OutputStream。要反向进行该过程,需要将一个InputStream封装到ObjectInputStream内,然后调用readObject()。我们最后获得的是一个引用,它指向一个向上转型的Object,所以必须向下转型才能直接设置它们。
<span style="font-size:18px;">import java.io.*;
import java.util.*;
class Data implements Serializable{
/**
*
*/
private int n;
public Data(int n){
this.n=n;
}
public String toString(){
return Integer.toString(n);
}
}
public class Worm implements Serializable{
/**
*
*/
private static Random rand =new Random(47);
private Data[] dat={
new Data(rand.nextInt(10)),
new Data(rand.nextInt(10)),
new Data(rand.nextInt(10))
};
private Worm next;
private char c;
public Worm(int i,char x){
System.out.println("Worm Constructor: "+i);
c=x;
if(--i>0){
next=new Worm(i,(char)(x+1));
}
}
public Worm(){
System.out.println("Default Constructor");
}
public String toString(){
StringBuilder result=new StringBuilder(":");
result.append(c);
result.append("(");
for(Data d:dat)
result.append(d);
result.append(")");
if(next!=null)
result.append(next);
return result.toString();
}
public static void main(String[] args) throws ClassNotFoundException,IOException{
Worm w1=new Worm(6,'a');
System.out.println("W1= "+w1);
ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream("worm.out"));
out.writeObject("worm storage\n");
out.writeObject(w1);
out.close();
ObjectInputStream in=new ObjectInputStream(new FileInputStream("worm.out"));
String s=(String)in.readObject();
Worm w2=(Worm)in.readObject();
System.out.println(s+"W2= "+w2);
in.close();
ByteArrayOutputStream bout=new ByteArrayOutputStream();
ObjectOutputStream out2=new ObjectOutputStream(bout);
out2.writeObject("worm storage\n");
out2.writeObject(w1);
out2.flush();
ObjectInputStream in2=new ObjectInputStream(
new ByteArrayInputStream(bout.toByteArray()));
s=(String)in2.readObject();
Worm w3=(Worm)in2.readObject();
System.out.println(s+"W3= "+w3);
}
}
</span>