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流的概念
-
它是指資料從源頭 流到 目的地,所以常把這種資料流叫做IO流。
-
I/O是Input/Output的縮寫,I/O技術是非常實用的技術,用於處理裝置之間的資料傳輸。如讀/寫檔案,網路通訊等。
-
Java程式中,對於資料的輸入/輸出操作以“流(stream)”的 方式進行。
-
java.io包下提供了各種“流”類和介面,用以獲取不同種類的 資料,並通過標準的方法輸入或輸出資料。
-
輸入input: 讀取外部資料(磁 盤、光碟等儲存裝置的資料)到 程式(記憶體)中。
- 輸出output: 將程式(記憶體) 資料輸出到磁碟、光碟等儲存設 備中。
1.3、流的分類
-
按操作資料單位不同分為: 位元組流(8 bit),字元流(16 bit)
-
按資料流的流向不同分為: 輸入流,輸出流
-
按流的角色的不同分為: 節點流,處理流
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
OutputStram
的write
方法,一次只能寫一個位元組。成功的向檔案中寫入了內容。但是並不高效,如何提高效率呢?可以使用緩衝,在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其實提供了專門的位元組流緩衝來提高效率。BufferedInputStream
和BufferedOutputStream。BufferedOutputStream
和BufferedOutputStream
類可以通過減少讀寫次數來提高輸入和輸出的速度。它們內部有一個緩衝區,用來提高處理效率。檢視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