標籤:io流
Java中的IO分為兩個部分,以InputStream和Reader為基類的輸入類,以OutputStream和Writer為基類的輸出類。其中InputStream和OutputStream以位元組為單位進行IO,而Reader和Writer以字元為單位。
除了輸入輸出,還有一系列類庫稱為Filter,或成為裝飾器。對於輸入可用FilterInputStream和FilterReader的衍生類別,輸出可用FilterOutputStream和FilterWriter的衍生類別,其中FilterInputStream和FilterOutputStream以位元組為單位,FilterReader和FilterWriter以字元為單位。
還有一個獨立與InputStream和OutputStream的—RandomAccessFile,用於對檔案的讀寫,有點類似與C語言中的fopen()
所以可以總結,所有以Stream結尾的都是以位元組為單位,也成為流;以Reader或Writer結尾的都以字元為單位。Reader和Writer在java1.1中才出現,如果需要進行轉換,可以使用InputStreamReader和OutputStreamWriter。
過濾器(Filter)
Filter是對輸入或輸出進行一定的控制,如緩衝、讀取或寫入基礎資料型別 (Elementary Data Type)等,用於更改流的一些行為。
FilterInputStream的衍生類別:
FilterOutputStream的衍生類別:
Reader和Writer中所用的Filter與InputStream和OutputStream中的Filter對比:
對於Filter的具體使用將在具體綜合例子中講到。
輸入
輸入分為輸入位元組和輸入字元,分別使用基類是InputStream和Reader,如果需要把InputStrema轉化為Reader,可以使用InputStreamReader。以下是一些InputStream常用的衍生類別與Writer與之對應的衍生類別。
InputStream衍生類別:
Reader與之對應的衍生類別:
將InputStream轉成Reader樣本:
// 建立一個InputStream類型的對象InputStream in = new FileInputStream("data.txt");// InputStreamReader繼承自Reader,其構造方法接受一個InputStream對象Reader reader = new InputStreamReader(in);
輸出
輸出分為輸出位元組和輸出字元,分別使用基類是OutputStream和Writer,如果需要把OutputStrema轉化為Writer,可以使用OutputStreamWriter。以下是一些OutputStream常用的衍生類別與Writer與之對應的衍生類別。
OutputStream衍生類別:
Writer與之對應的衍生類別:
將OutputStream轉成Writer樣本:
// 建立一個OutputStream類型的對象OutputStream out=new FileOutputStream("data.txt");// OutputStreamWriter繼承自Writer,其構造方法接受一個OutputStream對象Writer writer=new OutputStreamWriter(out);
綜合樣本
1、開啟一個檔案,並把其中的內容逐行輸出的螢幕上。為了提高效率,這裡將使用第一種過濾器BufferedReader,能夠對輸入進行緩衝。
public class Read { public static void main(String[]args) throws Exception{ String file="data.txt"; read(file); } public static void read(String file) throws Exception{ BufferedReader in=new BufferedReader(new FileReader(file)); String s; while((s=in.readLine())!=null) System.out.println(s); in.close(); }}
2、從檔案中按位元組讀取內容,需要用到DataInputStream過濾器,由於這裡要對位元組進行操作,所以要使用InputStream而不是Reader。其中對是否是用BufferedStream進行效率比較。
import java.io.*;public class ReadByte { public static void main(String[] args) throws Exception { String file = "data.txt"; long start; start = System.currentTimeMillis();// 記錄運行開始時間 readWithBufferedInputStream(file); System.out.println("readWithBufferedInputStream use time:" + (System.currentTimeMillis() - start));// 運行結束時間-開始時間就是已耗用時間 start = System.currentTimeMillis(); readWithoutBufferedInputStream(file); System.out.println("readWithoutBufferedInputStream use time:" + (System.currentTimeMillis() - start)); } public static void readWithBufferedInputStream(String file) throws Exception { // 用BufferedInputStream進行讀取檔案 DataInputStream in = new DataInputStream(new BufferedInputStream( new FileInputStream(file))); while (in.available() != 0) // DataInputStream剩餘的字元數不為零則表示還沒輸出結束 in.readByte(); in.close(); } public static void readWithoutBufferedInputStream(String file) throws Exception { // 不用BufferedInputStream讀取檔案 DataInputStream in = new DataInputStream(new FileInputStream(file)); while (in.available() != 0) in.readByte(); in.close(); }}
運行該程式,其中使用的data.txt檔案大小為5.4M,在我的電腦上的輸出為:
readWithBufferedInputStream use time:8775readWithoutBufferedInputStream use time:18487
顯然使用了BufferedInputStream效率高了不少。
3、java1.5以後為了方便檔案的輸入,添加了一個PrintWrite過濾器,它封裝了BufferedWriter,而且可以接受String類型的檔案名稱,所以可以精簡代碼。
import java.io.*;public class FileOutPut { public static void main(String[]args) throws Exception{ BufferedReader in=new BufferedReader(new FileReader("data.txt")); PrintWriter out=new PrintWriter("data1.txt"); String s; long start=System.currentTimeMillis(); while((s=in.readLine())!=null){ out.println(s);//用readLine讀取檔案時,每一行的斷行符號符會被去掉,所以寫入檔案的時候要把斷行符號符寫回去 } System.out.println("use time:"+(System.currentTimeMillis()-start)); in.close(); out.close(); }}
運行檔案同時可以發現,同樣是一樣大的data.txt檔案,讀出並寫出速度非常快,這個得益於緩衝。
4、由於之前的方法往檔案裡面寫入的是位元組或字元,沒有辦法儲存一些基本類型,所以要使用DataOutputStream/DataInputStream。
import java.io.*;public class ReadAndWriteBaseType { public static void main(String[] args) throws Exception { DataOutputStream out = new DataOutputStream(new FileOutputStream( "data1.txt")); out.writeUTF("This a String");// 寫入字串要用writeUTF(); out.writeInt(5); out.writeFloat(5.4f); out.close(); DataInputStream in = new DataInputStream(new FileInputStream( "data1.txt")); System.out.println(in.readFloat()); System.out.println(in.readInt()); System.out.println(in.readUTF());// 讀出字串要用readUTF(); in.close(); }}
5、使用RandomAccessFile進行讀寫檔案有點類似DataOutputStream/DataInputStream,都需要指定資料類型。但RandomAccessFile在建立對象的時候需要確定對檔案的操作類型,r/w/rw分別表示唯讀,唯寫,讀和寫。Seek()方法可以到處移動,在檔案的任意位置修改內容
import java.io.*;public class UsingRandomAccessFile { public static void main(String[] args) throws Exception { RandomAccessFile rf = new RandomAccessFile("data1.txt", "rw"); rf.writeInt(5); rf.writeInt(10); rf.writeInt(15); rf.writeInt(24); rf.close(); rf = new RandomAccessFile("data1.txt", "r"); System.out.println(rf.readInt()); System.out.println(rf.readInt()); System.out.println(rf.readInt()); System.out.println(rf.readInt()); rf.close(); rf = new RandomAccessFile("data1.txt", "rw"); rf.seek(0);// 把指標指向檔案開頭 rf.writeInt(-1);// 把前兩個位元組改成-1 rf.seek(0); System.out.println(rf.readInt()); System.out.println(rf.readInt()); System.out.println(rf.readInt()); System.out.println(rf.readInt()); rf.close(); }}
6、把標準輸入用BufferedReader封裝並擷取鍵盤輸入
public class Systemin { public static void main(String[] args) throws Exception { // System.in為InputStream類型,要通過InputStreamReader將其轉換成Reader BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); String s; while ((s = in.readLine()) != null) { System.out.println(s); } }}
6、重新導向,把控制台輸出、錯誤輸出定向到檔案,可用來寫記錄檔
import java.io.*;public class Redirect { public static void main(String[] args) throws Exception { OutputStream console = System.out; PrintStream out = new PrintStream(new BufferedOutputStream( new FileOutputStream("data1.txt"))); BufferedReader in = new BufferedReader(new InputStreamReader( new FileInputStream("data.txt"))); System.setOut(out);// 把輸出重新導向到out System.setErr(out);// 把錯誤資訊重新導向到out String s; while ((s = in.readLine()) != null) System.out.println(s);// 輸出被定向到out,所以不會在控制台輸出 out.close(); in.close(); }}
Java IO之簡單輸入輸出