java基礎學習總結——流

來源:互聯網
上載者:User

標籤:acl   div   myeclips   列印流   緩衝區   eof   空間   一模一樣   世界   

一、JAVA流式輸入/輸出原理

  

  流是用來讀寫資料的,java有一個類叫File,它封裝的是檔案的檔案名稱,只是記憶體裡面的一個對象,真正的檔案是在硬碟上的一塊空間,在這個檔案裡面存放著各種各樣的資料,我們想讀檔案裡面的資料怎麼辦呢?是通過一個流的方式來讀,咱們要想從程式讀資料,對於電腦來說,無論讀什麼類型的資料都是以010101101010這樣的形式讀取的。怎麼把檔案裡面的資料讀出來呢?你可以把檔案想象成一個小桶,檔案就是一個桶,檔案裡面的資料就相當於是這個桶裡面的水,那麼我們怎麼從這個桶裡面取水呢,也就是怎麼從這個檔案讀取資料呢。

  常見的取水的辦法是我們用一根管道插到桶上面,然後在管道的另一邊開啟水龍頭,桶裡面的水就開始嘩啦嘩啦地從水龍頭裡流出來了,桶裡面的水是通過這根管道流出來的,因此這根管道就叫流,JAVA裡面的流式輸入/輸出跟水流的原理一模一樣,當你要從檔案讀取資料的時候,一根管道插到檔案裡面去,然後檔案裡面的資料就順著管道流出來,這時你在管道的另一頭就可以讀取到從檔案流出來的各種各樣的資料了。當你要往檔案寫入資料時,也是通過一根管道,讓要寫入的資料通過這根管道嘩啦嘩啦地流進檔案裡面去。除了從檔案去取資料以外,還可以通過網路,比如用一根管道把我和你的機子串連起來,我說一句話,通過這個管道流進你的機子裡面,你馬上就可以看得到,而你說一句話,通過這根管道流到我的機子裡面,我也馬上就可以看到。有的時候,一根管道不夠用,比方說這根管道流過來的水有一些雜質,我們就可以在這個根管道的外面再包一層管道,把雜質給過濾掉。從程式的角度來講,從電腦讀取到的未經處理資料肯定都是010101這種形式的,一個位元組一個位元組地往外讀,當你這樣讀的時候你覺得這樣的方法不合適,沒關係,你再在這根管道的外面再包一層比較強大的管道,這個管道可以把010101幫你轉換成字串。這樣你使用程式讀取資料時讀到的就不再是010101這種形式的資料了,而是一些可以看得懂的字串了。

 二、輸入輸出資料流分類

  io包裡面定義了所有的流,所以一說流指的就是io包裡面的

  什麼叫輸入資料流?什麼叫輸出資料流?用一根管道一端插進檔案裡程式裡面,然後開始讀資料,那麼這是輸入還是輸出呢?如果站在檔案的角度上,這叫輸出,如果站在程式的角度上,這叫輸入。

  記住,以後說輸入資料流和輸出資料流都是站在程式的角度上來說。

三、節點流和處理流

  

   你要是對原始的流不滿意,你可以在這根管道外面再套其它的管道,套在其它管道之上的流叫處理流。為什麼需要處理流呢?這就跟水流裡面有雜質,你要過濾它,你可以再套一層管道過濾這些雜質一樣。

 3.1.節點流類型

  

  節點流就是一根管道直接插到資料來源上面,直接讀資料來源裡面的資料,或者是直接往資料來源裡面寫入資料。典型的節點流是檔案流:檔案的位元組輸入資料流(FileInputStream),檔案的位元組輸出資料流(FileOutputStream),檔案的字元輸入資料流(FileReader),檔案的字元輸出資料流(FileWriter)。

3.2.處理流類型

  

  處理流是包在別的流上面的流,相當於是包到別的管道上面的管道。

 四、InputStream(輸入資料流)

  

  我們看到的具體的某一些管道,凡是以InputStream結尾的管道,都是以位元組的形式向我們的程式輸入資料。

4.1.InputStream的基本方法

  

   read()方法是一個位元組一個位元組地往外讀,每讀取一個位元組,就處理一個位元組。read(byte[] buffer)方法讀取資料時,先把讀取到的資料填滿這個byte[]類型的數組buffer(buffer是記憶體裡面的一塊緩衝區),然後再處理數組裡面的資料。這就跟我們取水一樣,先用一個桶去接,等桶接滿水後再處理桶裡面的水。如果是每讀取一個位元組就處理一個位元組,這樣子讀取也太累了。

 五、OutputStream(輸出資料流)

  

5.1.OutputStream的基本方法

  

六、Reader流

  

6.1.Reader的基本方法

  

七、Writer流

  

7.1.Writer的基本方法

  

 八、節點流講解

  以File(檔案)這個類型作為講解節點流的典型代表

  

 範例:使用FileInputStream流來讀取FileInputStream.java檔案的內容

 1 package cn.galc.test; 2  3 import java.io.*; 4  5 public class TestFileInputStream { 6     public static void main(String args[]) { 7         int b = 0;// 使用變數b來裝調用read()方法時返回的整數 8         FileInputStream in = null; 9         // 使用FileInputStream流來讀取有中文的內容時,讀出來的是亂碼,因為使用InputStream流裡面的read()方法讀取內容時是一個位元組一個位元組地讀取的,而一個漢字是佔用兩個位元組的,所以讀取出來的漢字無法正確顯示。10         // FileReader in = null;//使用FileReader流來讀取內容時,中英文都可以正確顯示,因為Reader流裡面的read()方法是一個字元一個字元地讀取的,這樣每次讀取出來的都是一個完整的漢字,這樣就可以正確顯示了。11         try {12             in = new FileInputStream("D:\\Java\\MyEclipse 10\\Workspaces\\AnnotationTest\\src\\cn\\galc\\test\\FileInputStream.java");13             // in = new FileReader("D:/java/io/TestFileInputStream.java");14         } catch (FileNotFoundException e) {15             System.out.println("系統找不到指定檔案!");16             System.exit(-1);// 系統非正常退出17         }18         long num = 0;// 使用變數num來記錄讀取到的字元數19         try {// 調用read()方法時會拋異常,所以需要捕獲異常20             while ((b = in.read()) != -1) {21                 // 調用int read() throws Exception方法時,返回的是一個int類型的整數22                 // 迴圈結束的條件就是返回一個值-1,表示此時已經讀取到檔案的末尾了。23                 // System.out.print(b+"\t");//如果沒有使用“(char)b”進行轉換,那麼直接列印出來的b就是數字,而不是英文和中文了24                 System.out.print((char) b);25                 // “char(b)”把使用數字表示的漢字和英文字母轉換成字元輸入26                 num++;27             }28             in.close();// 關閉輸入資料流29             System.out.println();30             System.out.println("總共讀取了" + num + "個位元組的檔案");31         } catch (IOException e1) {32             System.out.println("檔案讀取錯誤!");33         }34     }35 }

範例:使用FileOutputStream流往一個檔案裡面寫入資料

 1 package cn.galc.test; 2  3 import java.io.*; 4  5 public class TestFileOutputStream { 6     public static void main(String args[]) { 7         int b = 0; 8         FileInputStream in = null; 9         FileOutputStream out = null;10         try {11             in = new FileInputStream("D:\\Java\\MyEclipse 10\\Workspaces\\AnnotationTest\\src\\cn\\galc\\test\\MyMouseAdapter.java");12             out = new FileOutputStream("D:/java/TestFileOutputStream1.java");13             // 指明要寫入資料的檔案,如果指定的路徑中不存在TestFileOutputStream1.java這樣的檔案,則系統會自動建立一個14             while ((b = in.read()) != -1) {15                 out.write(b);16                 // 調用write(int c)方法把讀取到的字元全部寫入到指定檔案中去17             }18             in.close();19             out.close();20         } catch (FileNotFoundException e) {21             System.out.println("檔案讀取失敗");22             System.exit(-1);// 非正常退出23         } catch (IOException e1) {24             System.out.println("檔案複製失敗!");25             System.exit(-1);26         }27         System.out28                 .println("TestFileInputStream.java檔案裡面的內容已經成功複製到檔案TestFileOutStream1.java裡面");29     }30 }

  FileInputStream和FileOutputStream這兩個流都是位元組流,都是以一個位元組為單位進行輸入和輸出的。所以對於佔用2個位元組儲存空間的字元來說讀取出來時就會顯示成亂碼。

 範例:使用FileWriter(字元流)向指定檔案中寫入資料

 1 package cn.galc.test; 2  3 /*使用FileWriter(字元流)向指定檔案中寫入資料 4 寫入資料時以1個字元為單位進行寫入*/ 5 import java.io.*; 6 public class TestFileWriter{ 7     public static void main(String args[]){ 8         /*使用FileWriter輸出資料流從程式把資料寫入到Uicode.dat檔案中 9         使用FileWriter流向檔案寫入資料時是一個字元一個字元寫入的*/10         FileWriter fw = null;11         try{12                 fw = new FileWriter("D:/java/Uicode.dat");13                 //字元的本質是一個無符號的16位整數14                 //字元在電腦內部佔用2個位元組15                 //這裡使用for迴圈把0~60000裡面的所有整數都輸出16                 //這裡相當於是把全世界各個國家的文字都0~60000內的整數的形式來表示17                 for(int c=0;c<=60000;c++){18                     fw.write(c);19                     //使用write(int c)把0~60000內的整數寫入到指定檔案內20                     //調用write()方法時,我認為在執行的過程中應該使用了“(char)c”進行強制轉換,即把整數轉換成字元來顯示21                     //因為開啟寫入資料的檔案可以看到,裡面顯示的資料並不是0~60000內的整數,而是不同國家的文字的表示方式22             }23             /*使用FileReader(字元流)讀取指定檔案裡面的內容24             讀取內容時是以一個字元為單位進行讀取的*/25                 int b = 0;26                 long num = 0;27                 FileReader fr = null;28                 fr = new FileReader("D:/java/Uicode.dat");29                 while((b = fr.read())!= -1){30                     System.out.print((char)b + "\t");31                     num++;32                 }33                 System.out.println();34                 System.out.println("總共讀取了"+num+"個字元");35         }catch(Exception e){36             e.printStackTrace();37         }38     }39 }

  FileReader和FileWriter這兩個流都是字元流,都是以一個字元為單位進行輸入和輸出的。所以讀取和寫入佔用2個位元組的字元時都可以正常地顯示出來,以上是以File(檔案)這個類型為例對節點流進行了講解,所謂的節點流指定就是直接把輸入資料流或輸出插入到資料來源上,直接往資料來源裡面寫入資料或讀取資料。

九、處理流講解 9.1.第一種處理流——緩衝流(Buffering)

   

  帶有緩衝區的,緩衝區(Buffer)就是記憶體裡面的一小塊地區,讀寫資料時都是先把資料放到這塊緩衝區域裡面,減少io對硬碟的訪問次數,保護我們的硬碟。可以把緩衝區想象成一個小桶,把要讀寫的資料想象成水,每次讀取資料或者是寫入資料之前,都是先把資料裝到這個桶裡面,裝滿了以後再做處理。這就是所謂的緩衝。先把資料放置到緩衝區上,等到緩衝區滿了以後,再一次把緩衝區裡面的資料寫入到硬碟上或者讀取出來,這樣可以有效地減少對硬碟的訪問次數,有利於保護我們的硬碟。

緩衝流測試代碼:

 1 package cn.gacl.test; 2  3 import java.io.*; 4  5 public class TestBufferStream { 6     public static void main(String args[]) { 7         FileInputStream fis = null; 8         try { 9             fis = new FileInputStream("D:/java/TestFileInputStream.java");10             // 在FileInputStream節點流的外面套接一層處理流BufferedInputStream11             BufferedInputStream bis = new BufferedInputStream(fis);12             int c = 0;13             System.out.println((char) bis.read());14             System.out.println((char) bis.read());15             bis.mark(100);// 在第100個字元處做一個標記16             for (int i = 0; i <= 10 && (c = bis.read()) != -1; i++) {17                 System.out.print((char) c);18             }19             System.out.println();20             bis.reset();// 重新回到原來標記的地方21             for (int i = 0; i <= 10 && (c = bis.read()) != -1; i++) {22                 System.out.print((char) c);23             }24             bis.close();25         } catch (FileNotFoundException e) {26             e.printStackTrace();27         } catch (Exception e1) {28             e1.printStackTrace();29         }30     }31 }
 1 package cn.gacl.test; 2  3 import java.io.*; 4 public class TestBufferStream1{ 5     public static void main(String args[]){ 6         try{ 7         BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\java\\dat.txt")); 8             //在節點流FileWriter的外面再套一層處理流BufferedWriter 9             String s = null;10             for(int i=0;i<100;i++){11                 s = String.valueOf(Math.random());//“Math.random()”將會產生一系列介於0~1之間的隨機數。12                 // static String valueOf(double d)這個valueOf()方法的作用就是把一個double類型的數轉換成字串13                 //valueOf()是一個靜態方法,所以可以使用“類型.靜態方法名”的形式來調用 14                 bw.write(s);//把隨機數字串寫入到指定檔案中15                 bw.newLine();//調用newLine()方法使得每寫入一個隨機數就換行顯示16             }17             bw.flush();//調用flush()方法清空緩衝區18             19         BufferedReader br = new BufferedReader(new FileReader("D:/java/dat.txt"));20                 //在節點流FileReader的外面再套一層處理流BufferedReader21             while((s = br.readLine())!=null){22                 //使用BufferedReader處理流裡面提供String readLine()方法讀取檔案中的資料時是一行一行讀取的23                 //迴圈結束的條件就是使用readLine()方法讀取資料返回的字串為空白值後則表示已經讀取到檔案的末尾了。24                 System.out.println(s);25                 26             }27         bw.close();28         br.close();29         }catch(Exception e){30             e.printStackTrace();31         }32     }33 }

  

  程式的輸入指的是把從檔案讀取到的內容儲存到為程式分配的記憶體地區裡面去。流,什麼是流,流無非就是兩根管道,一根向裡,一根向外,向裡向外都是對於我們自己寫的程式來說,流分為各種各樣的類型,不同的分類方式又可以分為不同的類型,根據方向來分,分為輸入資料流和輸出資料流,根據讀取資料的單位的不同,又可以分為字元流和位元組流,除此之外,還可以分為節點流和處理流,節點流就是直接和資料來源串連的流,處理流就是包在其它流上面的流,處理流不是直接和資料來源串連,而是從資料來源讀取到資料以後再通過處理流處理一遍。緩衝流也包含了四個類:BufferedInputStream、BufferedOutputStream、BufferedReader和BufferedWriter。流都是成對的,沒有流是是不成對的,肯定是一個in,一個out。

9.2.第二種處理流——轉換流

  

  轉換流非常的有用,它可以把一個位元組流轉換成一個字元流,轉換流有兩種,一種叫InputStreamReader,另一種叫OutputStreamWriter。InputStream是位元組流,Reader是字元流,InputStreamReader就是把InputStream轉換成Reader。OutputStream是位元組流,Writer是字元流,OutputStreamWriter就是把OutputStream轉換成Writer。把OutputStream轉換成Writer之後就可以一個字元一個字元地通過管道寫入資料了,而且還可以寫入字串。我們如果用一個FileOutputStream流往檔案裡面寫東西,得要一個位元組一個位元組地寫進去,但是如果我們在FileOutputStream流上面套上一個字元轉換流,那我們就可以一個字串一個字串地寫進去。

轉換流測試代碼:

 1 package cn.gacl.test; 2  3 import java.io.*; 4  5 public class TestTransform1 { 6     public static void main(String args[]) { 7         try { 8             OutputStreamWriter osw = new OutputStreamWriter( 9                     new FileOutputStream("D:/java/char.txt"));10             osw.write("MircosoftsunIBMOracleApplet");// 把字串寫入到指定的檔案中去11             System.out.println(osw.getEncoding());// 使用getEncoding()方法取得當前系統的預設字元編碼12             osw.close();13             osw = new OutputStreamWriter(new FileOutputStream(14                     "D:\\java\\char.txt", true), "ISO8859_1");15             // 如果在調用FileOutputStream的構造方法時沒有加入true,那麼新加入的字串就會替換掉原來寫入的字串,在調用構造方法時指定了字元的編碼16             osw.write("MircosoftsunIBMOracleApplet");// 再次向指定的檔案寫入字串,新寫入的字串加入到原來字串的後面17             System.out.println(osw.getEncoding());18             osw.close();19 20         } catch (Exception e) {21             e.printStackTrace();22         }23     }24 }

 1 package cn.gacl.test; 2  3 import java.io.*; 4 public class TestTransform2{ 5     public static void main(String args[]){ 6         try{ 7             InputStreamReader isr = new InputStreamReader(System.in); 8             //System.in這裡的in是一個標準的輸入資料流,用來接收從鍵盤輸入的資料 9             BufferedReader br = new BufferedReader(isr);10             String s = null;11             s = br.readLine();//使用readLine()方法把讀取到的一行字串儲存到字串變數s中去12             while(s != null){13                 System.out.println(s.toUpperCase());//把儲存在記憶體s中的字串列印出來14                 s = br.readLine();//在迴圈體內繼續接收從鍵盤的輸入15                 if(s.equalsIgnoreCase("exit")){16                     //只要輸入exit迴圈就結束,就會退出17                     break;18                 }19             }20         }catch(Exception e){21             e.printStackTrace();22         }23     }24 }

9.3.第三種處理流——資料流

  

資料流測試代碼:

 1 package cn.gacl.test; 2  3 import java.io.*; 4 public class TestDataStream{ 5     public static void main(String args[]){ 6         ByteArrayOutputStream baos = new ByteArrayOutputStream(); 7         //在調用構造方法時,首先會在記憶體裡面建立一個ByteArray位元組數組 8         DataOutputStream dos = new DataOutputStream(baos); 9         //在輸出資料流的外面套上一層資料流,用來處理int,double類型的數10         try{11             dos.writeDouble(Math.random());//把產生的隨機數直接寫入到位元組數組ByteArray中12             dos.writeBoolean(true);//布爾類型的資料在記憶體中就只佔一個位元組13         ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());14             System.out.println(bais.available());15             DataInputStream dis = new DataInputStream(bais);16             System.out.println(dis.readDouble());//先寫進去的就先讀出來,調用readDouble()方法讀取出寫入的隨機數17             System.out.println(dis.readBoolean());//後寫進去的就後讀出來,這裡面的讀取順序不能已變更位元置,否則會列印出不正確的結果18             dos.close();19             bais.close();20         }catch(Exception e){21                 e.printStackTrace();22             }23     }24 }

  通過bais這個流往外讀取資料的時候,是一個位元組一個位元組地往外讀取的,因此讀出來的資料無法判斷是字串還是bool類型的值,因此要在它的外面再套一個流,通過dataInputStream把讀出來的資料轉換就可以判斷了。注意了:讀取資料的時候是先寫進去的就先讀出來,因此讀ByteArray位元組數組資料的順序應該是先把佔8個位元組的double類型的數讀出來,然後再讀那個只佔一個位元組的boolean類型的數,因為double類型的數是先寫進數組裡面的,讀的時候也要先讀它。這就是所謂的先寫的要先讀。如果先讀Boolean類型的那個數,那麼讀出來的情況可能就是把double類型數的8個位元組裡面的一個位元組讀了出來。 

9.4.列印流——Print

  

測試代碼:

 1 package cn.gacl.test; 2  3 /*這個小程式是重新設定列印輸出的視窗, 4  * 把預設在命令列視窗輸出列印內容設定成其他指定的列印顯示視窗 5  */ 6 import java.io.*; 7 public class TestPrintStream{ 8     public static void main(String args[]){ 9         PrintStream ps = null;10         try{11                 FileOutputStream fos = new FileOutputStream("D:/java/log.txt");12                 ps = new PrintStream(fos);//在輸出資料流的外面套接一層列印流,用來控制列印輸出13                 if(ps != null){14                     System.setOut(ps);//這裡調用setOut()方法改變了輸出視窗,以前寫System.out.print()預設的輸出視窗就是命令列視窗.15                     //但現在使用System.setOut(ps)將列印輸出視窗改成了由ps指定的檔案裡面,通過這樣設定以後,列印輸出時都會在指定的檔案內列印輸出16                     //在這裡將列印輸出視窗設定到了log.txt這個檔案裡面,所以列印出來的內容會在log.txt這個檔案裡面看到17                 }18             for(char c=0;c<=60000;c++){19                     System.out.print(c+"\t");//把世界各國的文字列印到log.txt這個檔案中去20                 }21         }catch(Exception e){22             e.printStackTrace();23         }24     }25 }

  

9.5. 物件流程——Object

  

測試代碼:

 1 package cn.gacl.test; 2  3 import java.io.*; 4  5 public class TestObjectIo { 6     public static void main(String args[]) { 7         T t = new T(); 8         t.k = 8;// 把k的值修改為8 9         try {10             FileOutputStream fos = new FileOutputStream(11                     "D:/java/TestObjectIo.txt");12             ObjectOutputStream oos = new ObjectOutputStream(fos);13             // ObjectOutputStream流專門用來處理Object的,在fos流的外面套接ObjectOutputStream流就可以直接把一個Object寫進去14             oos.writeObject(t);// 直接把一個t對象寫入到指定的檔案裡面15             oos.flush();16             oos.close();17             FileInputStream fis = new FileInputStream(18                     "D:/java/TestObjectIo.txt");19             ObjectInputStream ois = new ObjectInputStream(fis);20             // ObjectInputStream專門用來讀一個Object的21             T tRead = (T) ois.readObject();22             // 直接把檔案裡面的內容全部讀取出來然後分解成一個Object對象,並使用強制轉換成指定類型T23             System.out.print(tRead.i + "\t" + tRead.j + "\t" + tRead.d + "\t"24                     + tRead.k);25             ois.close();26         } catch (Exception e) {27             e.printStackTrace();28         }29     }30 }31 32 /*33  * 凡是要將一個類的對象序列化成一個位元組流就必須實現Serializable介面34  * Serializable介面中沒有定義方法,Serializable介面是一個標記性介面,用來給類作標記,只是起到一個標記作用。35  * 這個標記是給編譯器看的,編譯器看到這個標記之後就可以知道這個類可以被序列化 如果想把某個類的對象序列化,就必須得實現Serializable介面36  */37 class T implements Serializable {38     // Serializable的意思是可以被序列化的39     int i = 10;40     int j = 9;41     double d = 2.3;42     int k = 15;43     // transient int k = 15;44     // 在聲明變數時如果加上transient關鍵字,那麼這個變數就會被當作是透明的,即不存在。45 }

  直接實現Serializable介面的類是JDK自動把這個類的對象序列化,而如果實現public interface Externalizable extends Serializable的類則可以自己控制對象的序列化,建議能讓JDK自己控制序列化的就不要讓自己去控制。

十、IO流總結

  

java基礎學習總結——流

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.