1. 程式人生 > >java基礎學習總結——流

java基礎學習總結——流

一、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.out
28                 .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 }
複製程式碼

  FileReaderFileWriter這兩個流都是字元流,都是以一個字元為單位進行輸入和輸出的。所以讀取和寫入佔用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節點流的外面套接一層處理流BufferedInputStream
11             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的外面再套一層處理流BufferedReader
21             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 }
複製程式碼

  

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

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

  

相關推薦

java基礎學習總結——

一、JAVA流式輸入/輸出原理      流是用來讀寫資料的,java有一個類叫File,它封裝的是檔案的檔名,只是記憶體裡面的一個物件,真正的檔案是在硬碟上的一塊空間,在這個檔案裡面存放著各種各樣的資料,我們想讀檔案裡面的資料怎麼辦呢?是通過一個流的方式來讀,咱

Java基礎學習總結(136)——有關資源關閉(try-with-resources與AutoCloseable)的使用總結

前言 做Java開發的都知道,每個資源的開啟都需要對應的關閉操作,不然就會使資源一直佔用而造成資源浪費,從而降低系統性能。關於資源的關閉操作,從JDK7-JDK9有了不少的提升及簡化。我們來看看資源處理的變化。 一、JDK6 在JDK6及之前,每個資源都需要我們手動寫程

JAVA基礎-學習總結-語法基礎

基本數據 heap 虛擬機 ont span 應該 內存 命名規則 循環 標識符的概念和命名規則 JAVA常量---不可變的變量 程序的執行過程 從現在開始,你應該記住,內存裏分四塊區域,code segment,data segment,stack,heap,

001 Java環境變數配置 java基礎學習總結——java環境變數配置

java基礎學習總結——java環境變數配置 前言   學習java的第一步就要搭建java的學習環境,首先是要安裝JDK,JDK安裝好之後,還需要在電腦上配置"JAVA_HOME”、"path”、"classpath"這三個環境變數才能夠把java的開發環境搭建好。在沒安裝過jdk的環境下,path環境

003 基礎語法2 java基礎學習總結——基礎語法2

java基礎學習總結——基礎語法2 一、語句    1.1. 條件語句   1.1.1 if語句   

002 基礎語法1 java基礎學習總結——基礎語法1

java基礎學習總結——基礎語法1  一.識別符號    二.關鍵字    三.JAVA基礎資料型別 3.1. java常量    3.2. java變數      從本質上來講,變數其實是記憶體裡面的一小塊區域,一個程式在執行的

005 異常處理 java基礎學習總結——異常處理

 java基礎學習總結——異常處理 一、異常的概念   異常指的是執行期出現的錯誤,也就是當程式開始執行以後執行期出現的錯誤。出現錯誤時觀察錯誤的名字和行號最為重要。    1 package cn.javastudy.summary; 2 3 p

java基礎學習總結(二十五):logback詳解

為什麼使用logback logback大約有以下的一些優點: 核心重寫、測試充分、初始化記憶體載入更小,這一切讓logback效能和log4j相比有諸多倍的提升 logback非常自然地直接實現了slf4j,這個嚴格來說算不上優點,只是這樣,再理解slf4j的前提下會很容易理解

java基礎學習總結(二十四):slf4j作用及其實現原理

簡單回顧門面模式 slf4j是門面模式的典型應用,因此在講slf4j前,我們先簡單回顧一下門面模式, 門面模式,其核心為外部與一個子系統的通訊必須通過一個統一的外觀物件進行,使得子系統更易於使用。用一張圖來表示門面模式的結構為:   門面模式的核心為Facade即門面

java基礎學習總結(二十三):什麼要使用AOP

從最基礎的原始程式碼-->使用設計模式(裝飾器模式與代理)-->使用AOP三個層次來講解一下為什麼我們要使用AOP。 原始程式碼的寫法 既然要通過程式碼來演示,那必須要有例子,這裡我的例子為: 有一個介面Dao有insert、delete、update三個方法,在insert

java基礎學習總結(二十二):Cglib及其基本使用

  Cglib是什麼           Cglib是一個強大的、高效能的程式碼生成包,它廣泛被許多AOP框架使用,為他們提供方法的攔截。下圖是我網上找到的一張Cglib與一些框架和語言的關係: 對此圖總結一下:

java基礎學習總結(二十一):自己寫一個java.lang.reflect.Proxy代理的實現

     動態代理裡面用到了一個類就是java.lang.reflect.Proxy,這個類是根據代理內容為傳入的介面生成代理用的。本文就自己寫一個Proxy類出來,功能和java.lang.reflect.Proxy一樣,傳入介面、代理內容,生成代理。  

java基礎學習總結(二十):多執行緒上下文切換

什麼是上下文切換        即使是單核CPU也支援多執行緒執行程式碼,CPU通過給每個執行緒分配CPU時間片來實現這個機制。時間片是CPU分配給各個執行緒的時間,因為時間片非常短,所以CPU通過不停地切換執行緒執行,讓我們感覺多個執行緒時同時執行的,時

java基礎學習總結(十九):Unsafe與CAS

Unsafe         簡單講一下這個類。Java無法直接訪問底層作業系統,而是通過本地(native)方法來訪問。不過儘管如此,JVM還是開了一個後門,JDK中有一個類Unsafe,它提供了硬體級別的原子操作。     &n

java基礎學習總結(十八):切勿用普通for迴圈遍歷LinkedList

ArrayList與LinkedList的普通for迴圈遍歷 對於大部分Java程式設計師朋友們來說,可能平時使用得最多的List就是ArrayList,對於ArrayList的遍歷,一般用如下寫法: public static void main(String[] args) {

java基礎學習總結(十七):Java Socket

一、 什麼是Socket          Socket的概念很簡單,它是網路上執行的兩個程式間雙向通訊的一端,既可以接收請求,也可以傳送請求,利用它可以較為方便地編寫網路上資料的傳遞。 所以簡而言之,Socket就是程序通訊的端點

java基礎學習總結(十六):程式碼優化

程式碼優化的目標是: 1、減小程式碼的體積 2、提高程式碼執行的效率 程式碼優化細節 (1)儘量指定類、方法的final修飾符     帶有final修飾符的類是不可派生的。在Java核心API中,有許多應用final的例子,例如java.lang.Strin

java基礎學習總結(十五):抽象類與介面

       抽象類與介面是java語言中對抽象概念進行定義的兩種機制,正是由於他們的存在才賦予java強大的面向物件的能力。他們兩者之間對抽象概念的支援有很大的相似,甚至可以互換,但是也有區別。  一、抽象類    &n

java基礎學習總結(十四):Enum 型別的使用介紹

一、Enum 型別的介紹    列舉型別(Enumerated Type) 很早就出現在程式語言中,它被用來將一組類似的值包含到一種型別當中。而這種列舉型別的名稱則會被定義成獨一無二的型別描述符,在這一點上和常量的定義相似。不過相比較常量型別,列舉型別可以為宣告的變

java基礎學習總結(十三):Java異常處理

一、JAVA異常       異常是指不期而至的各種情況,如:檔案找不到、網路連線失敗、非法引數等。異常是一個事件,它發生在程式執行期間,干擾了正常的指令流程。Java通過API中的Throwable類的眾多子類描述各種不同的異常。因而,Java異常都是物件,是Th