IO流這個體系中,涉及到了很多設備,有硬盤、控制檯、鍵盤、內存、打印機、掃描儀。。。,如果說,以客戶爲中心,那麼我們的大客戶就是內存了,所有這些輸入輸出設備都是爲了輔助內存而存在的。
總體來說,這些外設分爲3類,文件類、控制檯、鍵盤輸入,如果還要說一個,那就是網卡了,對於網卡暫時不討論。 IO的I指的是Input,那麼Input操作的對象時誰?IO的O指的是Output,那麼Output操作的對象又是誰呢?這兩個都是動詞耶,他們必須要操作一個實體啊,不多想,這個實體就是內存了,具體點說是內存中某一個對象了。Input,就像你往水杯裏面裝水,Output,那就像你把杯子裏面的水倒出來一樣了,那麼裝水倒水這些動作,到底是屬於我們的,還是屬於杯子的呢???
以前,用到IO流中比較多的就是控制檯和鍵盤了:System.out 和System.in,那麼現在來看看文件操作。需求是:將“D:\\a.java"拷貝到"E:\\b.java",也就是說在E盤下創建一下叫b.java的文件,它具有和a.java一樣的內容,那麼這將是一個怎樣的流程呢?1首先,要處理硬盤上面的文件,必須在內存中爲這個文件建立一個File對象,與之映射,我們只用抽象的處理這個File對象,底層就會爲我們具體的操作硬盤了。但是File對象
只能操作自己,無法和其他File對象交互,不可能說一個File對象將自己的內容直接發送給另一個File對象了,這時候流就出現了。
流程:源文件-源File對象-輸入流對象-內存中轉站-輸出流對象-目的File對象-目的文件,而我們只需要操作輸入流、中轉站和輸出流了,流和中轉站都這麼多,我們又該怎麼選擇呢?
2然後,就是尋找適合的流對象了和中轉站了。java中的流按照輸入輸出,分爲輸入流和輸出流,這個不用多說了。還有就是字節流和字符流,原本只有字節流的,因爲內存裏面本來就只能存儲0101了,後來爲了能方便操作字符,就在字節流上面進行了包裝。再後來,爲了各種需求和效率問題,又有了緩衝流、字節字符轉換流...等等,就像以前只有泥巴路一樣,後來爲了走車子,有了柏油路,爲了走火車,又有了鐵路,爲了走地鐵,又有了地鐵線路。。。。都是隨着需求不斷改變的。
上面的源文件a.java是純文本字符的,所以選擇字符輸入流了,即Reader類,爲了提高效率,選擇BufferedReader,
目的文件b.java 也是純文本的,所以徐那種字符輸出流了,即Writer,爲了提高效率,就選BufferedWriter了。
中轉站怎麼選呢?我操作文件時,是一行行操作,還是一個個字符,還是一塊塊的?算了,都試一試,看哪個的效率高了。一個個字符操作,用char;一行行的話
用個String;一塊塊的話,就用個char[]了。
3代碼示例:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
//爲了方便看邏輯,將所有的異常都拋出去了。
public class CopyTextFile {
public static void main(String[] args) throws IOException{
long start1=System.currentTimeMillis();
copy_1();
long time1=System.currentTimeMillis()-start1;
System.out.println("一行行的讀,耗時:"+time1);
long start2=System.currentTimeMillis();
copy_2();
long time2=System.currentTimeMillis()-start2;
System.out.println("一塊塊的讀,耗時:"+time2);
long start3=System.currentTimeMillis();
copy_3();
long time3=System.currentTimeMillis()-start3;
System.out.println("一個個字符的讀,耗時:"+time3);
}
public static void copy_1() throws IOException {
//1輸入流:BufferedReader
BufferedReader bufr=new BufferedReader(new FileReader("D:\\a.java"));
//2輸出流:BufferedWriter
BufferedWriter bufw=new BufferedWriter(new FileWriter("E:\\b1.java"));
//3:內存中轉站
//①String:從輸入流中讀取一行暫存String,在將String寫到輸出流,記得換行和刷新
String line =null;
while((line=bufr.readLine())!=null)
{
bufw.write(line);
bufw.newLine();
bufw.flush();
}
//關閉流:就像用完水龍頭一樣,要及時的關閉,免得浪費了資源
bufr.close();
bufw.close();
}
public static void copy_2() throws IOException{
//1輸入流:BufferedReader
BufferedReader bufr=new BufferedReader(new FileReader("D:\\a.java"));
//2輸出流:BufferedWriter
BufferedWriter bufw=new BufferedWriter(new FileWriter("E:\\b2.java"));
//3:內存中轉站
//②char[]:從輸入流讀一塊數據存到char[],再把這存的數據丟到輸出流
char[]buf=new char[1024];
int num=0;
while((num=bufr.read(buf))!=-1)
{
bufw.write(buf,0,num);
}
//關閉流:就像用完水龍頭一樣,要及時的關閉,免得浪費了資源
bufr.close();
bufw.close();
}
public static void copy_3() throws IOException{
//1輸入流:BufferedReader
BufferedReader bufr=new BufferedReader(new FileReader("D:\\a.java"));
//2輸出流:BufferedWriter
BufferedWriter bufw=new BufferedWriter(new FileWriter("E:\\b3.java"));
//3:內存中轉站:
//③char字符:從輸入流讀一個字符到char,在將char寫入到輸出流,(由於char會被自動提示爲int,所以需要使用int進行轉換)
int ch=0;
while((ch=bufr.read())!=-1){
bufw.write(ch);
}
//關閉流:就像用完水龍頭一樣,要及時的關閉,免得浪費了資源
bufr.close();
bufw.close();
}
}
一行行的讀,耗時:0
一塊塊的讀,耗時:0
一個個字符的讀,耗時:0
原來使用了Buffer,這幾種方式都在在內存裏面,速度比較快,時間幾乎都是0毫秒了。但是,對於文本文件,建議用一行行的讀,可以有效的提取數據。
待續。。。。
換個一個500kb的文件測試,隨機一個結果是:
一行行的讀,耗時:64
一塊塊的讀,耗時:7
一個個字符的讀,耗時:20
發現一行行讀最慢,其次一個個讀寫,最快一塊塊。有業務邏輯,需要判斷某行內容,一行行讀吧,需要判斷某一個字符,一個個字符讀吧,如果只是拷貝文件,建議一塊塊的讀,而且不改變文件大小。