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>