1. 程式人生 > 實用技巧 >Item 4: Enforce noninstantiability with a private constructor.

Item 4: Enforce noninstantiability with a private constructor.

一、IO流基本概念

1.1、位元(Bit)、位元組(Byte)、字元(Char)

  • Bit 位,是計算機最小的二進位制單位 ,取0或1,主要用於計算機操作。

  • Byte 位元組,是資料的最小單位,由8位bit組成,取值(-128-127),主要用於計算機操作資料。

  • Char 字元,是使用者可讀寫的最小單位,由16位bit(2個byte)組成,取值(0-65535),主要用於使用者操數資料。

1.2、IO流的概念

  1. 它是指資料從源頭 流到 目的地,所以常把這種資料流叫做IO流。

  2. I/O是Input/Output的縮寫,I/O技術是非常實用的技術,用於處理裝置之間的資料傳輸。如讀/寫檔案,網路通訊等。

  3. Java程式中,對於資料的輸入/輸出操作以“流(stream)”的 方式進行。 

  4. java.io包下提供了各種“流”類和介面,用以獲取不同種類的 資料,並通過標準的方法輸入或輸出資料。  

  5. 輸入input: 讀取外部資料(磁 盤、光碟等儲存裝置的資料)到 程式(記憶體)中。

  6. 輸出output: 將程式(記憶體) 資料輸出到磁碟、光碟等儲存設 備中。

1.3、流的分類

  1. 按操作資料單位不同分為: 位元組流(8 bit)字元流(16 bit)

  2. 按資料流的流向不同分為: 輸入流輸出流

  3. 按流的角色的不同分為: 節點流處理流

  

1.4、IO流體系

    

  1、Java的IO流共涉及40多個類,實際上非常規則,都是從如下4個 抽象基類派生的。

  2、由這四個類派生出來的子類名稱都是以其父類名作為子類名字尾。

  

  IO流繼承體系

  

二、位元組流

2.1、Inpustream

  InputStream有read方法,一次讀取一個位元組,OutputStream的write方法一次寫一個int。這兩個類都是抽象類。意味著不能建立物件,那麼需要找到具體的子類來使用。操作流的步驟都是:

  第一步:1:例項化File類物件

  第二步:2:開啟流(即建立流)

  第三步:3:通過流讀取內容

  第四步:4:用完後,關閉流資源

  案例一:使用read()方法,一次讀取一個位元組,讀到檔案末尾返回-1.

 1 public void testFileInputStream() {
 2     // 1、例項化File類物件
 3     File file = new File("hello.txt");
 4     // 2、提供具體流
 5     FileInputStream fis = null;
 6     try {
 7         fis = new FileInputStream(file);
 8         // 3、資料讀取
 9         // read():返回讀入的一個字元。如果達到檔案末尾了,返回-1
10         int data;
11         while ( (data=fis.read()) != -1) {
12             System.out.print((char) data);
13         }
14 
15     } catch (IOException e) {
16         e.printStackTrace();
17 
18     } finally {
19         // 4、關閉流
20         if (fis != null) {
21             try {
22                 fis.close();
23             } catch (IOException e) {
24                 e.printStackTrace();
25             }
26         }
27     }
28 }
View Code

  案例二(推薦使用):使用read()方法的時候,可以將讀到的資料裝入到位元組陣列中,相當於緩衝(提高效率),並迴圈讀取(讀完所有內容).

 1 public void testFileInputStream() {
 2     // 1、造檔案
 3     File file = new File("hello.txt");
 4 
 5     // 2、造輸入流
 6     FileInputStream fileInputStream = null;
 7     try {
 8         fileInputStream = new FileInputStream(file);
 9 
10         // 3、讀資料
11         byte[] buffer = new byte[5];
12         int len;
13         while ((len = fileInputStream.read(buffer)) != -1) {
14             System.out.print(new String(buffer, 0, len));
15         }
16 
17     } catch (FileNotFoundException e) {
18         e.printStackTrace();
19     } catch (IOException e) {
20         e.printStackTrace();
21     } finally {
22         // 4、關閉流資源
23         if (fileInputStream != null) {
24             try {
25                 fileInputStream.close();
26             } catch (IOException e) {
27                 e.printStackTrace();
28             }
29         }
30     }
31 }
View Code  

2.2、OutputStream

  OutputStramwrite方法,一次只能寫一個位元組。成功的向檔案中寫入了內容。但是並不高效,如何提高效率呢?可以使用緩衝,在OutputStram類中有write(byte[] b)方法,將b.length個位元組從指定的byte陣列寫入此輸出流中。

  操作步驟與讀取類似

 1 public void testFileOutputStream() {
 2     // 1、提供File類物件,並指明寫出的檔案
 3     File file = new File("hello2.txt");
 4 
 5     // 2、提供FileOutputStream的物件,用於資料的寫出
 6     FileOutputStream fos = null;
 7     try {
 8         // 第二個引數,是否在原檔案上追加內容,預設為false
 9         fos = new FileOutputStream(file, true);
10 
11         // 3、寫出的操作
12         fos.write("I have a Dream".getBytes());
13 
14     } catch (IOException e) {
15         e.printStackTrace();
16     } finally {
17         // 4、流資源的關閉
18         if (fos != null) {
19             try {
20                 fos.close();
21             } catch (IOException e) {
22                 e.printStackTrace();
23             }
24         }
25     }
26 
27 }
View Code

2.3、輸入輸出流綜合使用——檔案拷貝實現

  可以根據拷貝的需求調整陣列的大小,一般是1024的整數倍。使用緩衝後效率大大提高。目前我們是丟擲處理,一旦出現了異常,close就沒有執行,也就沒有釋放資源。那麼為了保證close的執行該如何處理呢。那麼就需要使用try{} catch(){}finally{}語句。try中放入可能出現異常的語句,catch是捕獲異常物件,fianlly是一定要執行的程式碼。1publicvoid testFileInputOutputStream() {2// 1、建立File類的物件,指明讀入和寫出的檔案3 File srcFile = new File("tomcat.png"); 4 File destFile = new File("tomcat2.png"); 5 6 7// 2、建立輸入流和輸出流的物件 8 FileInputStream fileInputStream = null; 9 FileOutputStream fileOutputStream = null; 10try { 11 fileInputStream = new FileInputStream(srcFile); 12 fileOutputStream = new FileOutputStream(destFile); 1314// 3、資料的讀入和寫出操作15byte[] cbuf = newbyte[1024]; 16int len; 17while ((len = fileInputStream.read(cbuf)) != -1) { 18 fileOutputStream.write(cbuf, 0, len); 19 } 20 } catch (FileNotFoundException e) { 21 e.printStackTrace(); 22 } catch (IOException e) { 23 e.printStackTrace(); 24 } finally { 2526// 4、關閉流資源27if (fileOutputStream != null) { 28try { 29 fileOutputStream.close(); 30 } catch (IOException e) { 31 e.printStackTrace(); 32 } 33 } 34if (fileInputStream != null) { 35try { 36 fileInputStream.close(); 37 } catch (IOException e) { 38 e.printStackTrace(); 39 } 40 } 4142 } 43 }  

三、字元流

  計算機並不區分二進位制檔案與文字檔案。所有的檔案都是以二進位制形式來儲存的,因此,從本質上說,所有的檔案都是二進位制檔案。所以字元流是建立在位元組流之上的,它能夠提供字元層次的編碼和解碼。可以說字元流就是:位元組流 + 編碼表,為了更便於操作文字資料。字元流的抽象基類:Reader , Writer。由這些類派生出來的子類名稱都是以其父類名作為子類名的字尾,如FileReader、FileWriter

檔案拷貝實現示例
 1 public void testFileReaderFileWriter() {
 2     // 1、建立File類的物件,指明讀入和寫出的檔案
 3     File srcFile = new File("hello.txt");
 4     File destFile = new File("hello2.txt");
 5 
 6     // 2、建立輸入流和輸出流的物件
 7     FileReader fileReader = null;
 8     FileWriter fileWriter = null;
 9     try {
10         fileReader = new FileReader(srcFile);
11         fileWriter = new FileWriter(destFile);
12 
13         // 3、資料的讀入和寫出操作
14         char[] cbuf = new char[5];
15         int len;
16         while ((len = fileReader.read(cbuf)) != -1) {
17             fileWriter.write(cbuf, 0, len);
18         }
19     } catch (FileNotFoundException e) {
20         e.printStackTrace();
21     } catch (IOException e) {
22         e.printStackTrace();
23     } finally {
24 
25         // 4、關閉流資源
26         if(fileWriter != null ){
27             try {
28                 fileWriter.close();
29             } catch (IOException e) {
30                 e.printStackTrace();
31             }
32         }
33         if (fileReader != null) {
34             try {
35                 fileReader.close();
36             } catch (IOException e) {
37                 e.printStackTrace();
38             }
39         }
40 
41     }
42 }
* 結論:
* 1、對於文字檔案(.txt,.java,.c,.cpp),使用字元流處理
* 2、對於非文字檔案(.jpg,.mp3,.mp4,.avi,.doc,.ppt),使用位元組流檔案

四、緩衝流

  Java其實提供了專門的位元組流緩衝來提高效率。BufferedInputStreamBufferedOutputStream。BufferedOutputStreamBufferedOutputStream類可以通過減少讀寫次數來提高輸入和輸出的速度。它們內部有一個緩衝區,用來提高處理效率。檢視API文件,發現可以指定緩衝區的大小。其實內部也是封裝了位元組陣列。沒有指定緩衝區大小,預設的位元組是8192。顯然緩衝區輸入流和緩衝區輸出流要配合使用。首先緩衝區輸入流會將讀取到的資料讀入緩衝區,當緩衝區滿時,或者呼叫flush方法,緩衝輸出流會將資料寫出。
注意:當然使用緩衝流來進行提高效率時,對於小檔案可能看不到效能的提升。但是檔案稍微大一些的話,就可以看到實質的效能提升了。

檔案拷貝實現示例

 1 public void bufferedStreamTest(){
 2     // 1、造檔案
 3     File srcFile = new File("hello.txt");
 4     File destFile = new File("hello2.txt");
 5 
 6     // 2、造流
 7     // 2.1、造節點流
 8     FileInputStream fis = null;
 9     FileOutputStream fos = null;
10     BufferedInputStream bis = null;
11     BufferedOutputStream bos = null;
12     try {
13         fis = new FileInputStream(srcFile);
14         fos = new FileOutputStream(destFile);
15 
16         // 2.2、造緩衝流
17         bis = new BufferedInputStream(fis);
18         bos = new BufferedOutputStream(fos);
19 
20         // 3、複製的細節:讀取、寫入
21         byte[] buffer = new byte[1024];
22         int len;
23         while ((len = bis.read(buffer)) != -1) {
24             bos.write(buffer, 0, len);
25 
26             // 重新整理緩衝區,手動將buffer中的資料寫入檔案
27 //                bos.flush();
28         }
29     } catch (FileNotFoundException e) {
30         e.printStackTrace();
31     } catch (IOException e) {
32         e.printStackTrace();
33     } finally {
34 
35         // 4、資源關閉
36         // 要求:先關閉外層的流,在關閉內層的流
37         if(bos != null) {
38             try {
39                 bos.close();
40             } catch (IOException e) {
41                 e.printStackTrace();
42             }
43         }
44         if(bis != null) {
45             try {
46                 bis.close();
47             } catch (IOException e) {
48                 e.printStackTrace();
49             }
50         }
51         // 說明:在關閉外層流的同時,內層流也會自動的進行關閉
52         // 關閉內層流的操作,可以忽略
53 //        fos.close();
54 //        fis.close();
55     }
56 }

五、轉換流

1、轉換流提供了在位元組流和字元流之間的轉換

  2、Java API提供了兩個轉換流:

    1)InputStreamReader:將InputStream轉換為Reader

    2)OutputStreamWriter:將Writer轉換為OutputStream

  3、位元組流中的資料都是字元時,轉成字元流操作更高效。

  4、很多時候我們使用轉換流來處理檔案亂碼問題。實現編碼和 解碼的功能。

  示例程式碼如下:

 1 public void test2() {
 2     InputStreamReader isr = null;
 3     OutputStreamWriter osw = null;
 4 
 5     try {
 6         FileInputStream fis = new FileInputStream("hello.txt");
 7         FileOutputStream fos = new FileOutputStream("hello2.txt");
 8 
 9         isr = new InputStreamReader(fis, "utf-8");
10         osw = new OutputStreamWriter(fos, "gbk");
11 
12         char[] cbuf = new char[5];
13         int len;
14         while ((len = isr.read(cbuf)) != -1) {
15             String str = new String(cbuf, 0, len);
16             System.out.print(str);
17             osw.write(str);
18         }
19 
20     } catch (FileNotFoundException e) {
21         e.printStackTrace();
22     } catch (UnsupportedEncodingException e) {
23         e.printStackTrace();
24     } catch (IOException e) {
25         e.printStackTrace();
26     } finally {
27         if(osw != null){
28             try {
29                 osw.close();
30             } catch (IOException e) {
31                 e.printStackTrace();
32             }
33         }
34         if (isr != null) {
35             try {
36                 isr.close();
37             } catch (IOException e) {
38                 e.printStackTrace();
39             }
40 
41         }
42     }
43 }
View Code

六、其他流介紹

6.1、標準輸入、輸出流(瞭解)

  •  System.in和System.out分別代表了系統標準的輸入和輸出裝置

  •  預設輸入裝置是:鍵盤,輸出裝置是:顯示器

  •  System.in的型別是InputStream

  •  System.out的型別是PrintStream,其是OutputStream的子類FilterOutputStream的子類

  •  重定向:通過System類的setIn,setOut方法對預設裝置進行改變。

      public static voidsetIn(InputStream in)
      public static voidsetOut(PrintStream out)

6.2、列印流(瞭解)

  實現將基本資料型別的資料格式轉化為字串輸出

列印流:PrintStream和PrintWriter

  •  提

  •  PrintStream和PrintWriter的輸出不會丟擲IOException異常

  •  PrintStream和PrintWriter有自動flush功能

  •  PrintStream列印的所有字元都使用平臺的預設字元編碼轉換為位元組。

      在需要寫入字元而不是寫入位元組的情況下,應該使用PrintWriter類。

  •  System.out返回的是PrintStream的例項

6.3、資料流(瞭解)

  1、為了方便地操作Java語言的基本資料型別和String的資料,可以使用資料流

  2、資料流有兩個類:(用於讀取和寫出基本資料型別、String類的資料)

    DataInputStream 和 DataOutputStream

    分別“套接”在 InputStream 和 OutputStream 子類的流上

  3、DataInputStream中的方法

    • boolean readBoolean()
    • char readChar()
    • double readDouble()
    • long readLong()
    • String readUTF()
    • byte readByte()
    • float readFloat()
    • short readShort()
    • int readInt()
    • void readFully(byte[] b)

  4、DataOutputStream中的方法
    將上述的方法的read改為相應的write即可。

 1 /**
 2  * 資料流 DataInputStream 和 DataOutputStream
 3  * 作用:用於讀取和寫出基本資料型別的變數或字串
 4  *
 5  */
 6 public void testDataOutputStream(){
 7     DataOutputStream dos = null;
 8     try {
 9         dos = new DataOutputStream(new FileOutputStream("d.txt"));
10 
11         dos.writeUTF("中國人");
12         dos.flush(); // 重新整理操作,一定執行就會將資料寫入檔案
13         dos.writeInt(12);
14         dos.writeDouble(1.1);
15         dos.writeBoolean(true);
16     } catch (FileNotFoundException e) {
17         e.printStackTrace();
18     } catch (IOException e) {
19         e.printStackTrace();
20     } finally {
21         if(dos != null) {
22             try {
23                 dos.close();
24             } catch (IOException e) {
25                 e.printStackTrace();
26             }
27         }
28     }
29 
30 }
31 
32 public void testDataInputStream(){
33     DataInputStream dis = null;
34     try {
35         dis = new DataInputStream(new FileInputStream("d.txt"));
36 
37         String str = dis.readUTF();
38         System.out.println(str);
39         int num = dis.readInt();
40         System.out.println(num);
41         double dou = dis.readDouble();
42         System.out.println(dou);
43         boolean b = dis.readBoolean();
44         System.out.println(b);
45     } catch (FileNotFoundException e) {
46         e.printStackTrace();
47     } catch (IOException e) {
48         e.printStackTrace();
49     } finally {
50         if(dis != null) {
51             try {
52                 dis.close();
53             } catch (IOException e) {
54                 e.printStackTrace();
55             }
56         }
57     }
58 
59 }
View Code