Java中的IO分爲兩個部分,以InputStream和Reader爲基類的輸入類,以OutputStream和Writer爲基類的輸出類。其中InputStream和OutputStream以字節爲單位進行IO,而Reader和Writer以字符爲單位。java
除了輸入輸出,還有一系列類庫稱爲Filter,或成爲裝飾器。對於輸入可用FilterInputStream和FilterReader的派生類,輸出可用FilterOutputStream和FilterWriter的派生類,其中FilterInputStream和FilterOutputStream以字節爲單位,FilterReader和FilterWriter以字符爲單位。緩存
還有一個獨立與InputStream和OutputStream的—RandomAccessFile,用於對文件的讀寫,有點相似與C語言中的fopen()markdown
因此能夠總結,全部以Stream結尾的都是以字節爲單位,也成爲流;以Reader或Writer結尾的都以字符爲單位。Reader和Writer在java1.1中才出現,若是須要進行轉換,能夠使用InputStreamReader和OutputStreamWriter。dom
Filter是對輸入或輸出進行必定的控制,如緩存、讀取或寫入基本數據類型等,用於更改流的一些行爲。spa
FilterInputStream的派生類:指針
FilterOutputStream的派生類:日誌
Reader和Writer中所用的Filter與InputStream和OutputStream中的Filter對比:code
對於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);
一、打開一個文件,並把其中的內容逐行輸出的屏幕上。爲了提升效率,這裏將使用第一種過濾器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(); } }
二、從文件中按字節讀取內容,須要用到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:8775 readWithoutBufferedInputStream use time:18487
顯然使用了BufferedInputStream效率高了很多。
三、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文件,讀出並寫出速度很是快,這個得益於緩存。
四、因爲以前的方法往文件裏面寫入的是字節或字符,沒有辦法存儲一些基本類型,因此要使用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(); } }
五、使用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(); } }
六、把標準輸入用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); } } }
六、重定向,把控制檯輸出、錯誤輸出定向到文件,可用來寫日誌文件
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(); } }