Java基礎(八)——IO流2_緩衝流、轉換流

L發表於2022-01-01

一、緩衝流

1、介紹

  緩衝流:不能直接作用在檔案上,需要包一層,它是一種處理流。用於提高檔案的讀寫效率。它在流的基礎上對流的功能進行了增強。提高讀寫速度的原因:內部提供了一個緩衝區。預設使用 8192 個位元組(8Kb)的緩衝區 。
  原始碼示例:BufferedInputStream

1 public class BufferedInputStream extends FilterInputStream {
2     // 預設緩衝區的大小
3     private static int DEFAULT_BUFFER_SIZE = 8192;
4 }

  要求:先關閉外層的流,再關閉內層的流。而關閉外層流的同時,內層流也會自動的進行關閉。關於內層流的關閉,可以省略。

2、BufferedInputStream,BufferedOutputStream(位元組流的緩衝區)

  程式碼示例:用位元組流緩衝區處理非文字檔案(圖片,視訊等)。緩衝流複製圖片。

 1 // 檔案:F:\\hello.jpg
 2 public class Main {
 3 
 4     public static void main(String[] args) {
 5         try (// 造節點流
 6              FileInputStream fis = new FileInputStream((new File("F:\\hello.jpg")));
 7              FileOutputStream fos = new FileOutputStream(new File("F:\\hello_1.jpg"));
 8              // 造緩衝流
 9              BufferedInputStream bis = new BufferedInputStream(fis);
10              BufferedOutputStream bos = new BufferedOutputStream(fos);) {
11 
12             byte[] buffer = new byte[1024];
13             int len;
14             while ((len = bis.read(buffer)) != -1) {
15                 bos.write(buffer, 0, len);
16             }
17 
18             // 重新整理緩衝區.必須
19             // bos.flush();
20         } catch (Exception e) {
21         }
22     }
23 }
24 
25 // 用於copy 3.64G 的檔案花費 18.925s

3、BufferedReader、BufferedWriter(字元流的緩衝區)

  BufferedReader:從字元輸入流中讀取文字,緩衝各個字元,從而實現字元、陣列和行的高效讀取。可以指定緩衝區的大小,或者使用預設的大小。在大多數情況下,預設值就足夠大了。
  字元讀取流緩衝區,該緩衝區提供了一個一次讀一行的方法readLine(),方便於對文字資料的獲取。當返回null時,表示讀到檔案末尾。
  BufferedWriter:將文字寫入字元輸出流,緩衝各個字元,從而提供單個字元、陣列和字串的高效寫入。可以指定緩衝區的大小,或者接受預設的大小。在大多數情況下,預設值就足夠大了。
  該緩衝區中提供了一個跨平臺的換行符:newLine()。
  程式碼示例:用字元流緩衝區處理文字檔案。緩衝流複製文字檔案。

 1 // 檔案:F:\\hello.txt
 2 // 內容:任意
 3 
 4 // 方式一:會自動換行
 5 public class Main {
 6 
 7     public static void main(String[] args) {
 8         try ( // 造節點流
 9               FileReader fr = new FileReader(new File("F:\\hello.txt"));
10               FileWriter fw = new FileWriter(new File("F:\\hello_1.txt"));
11 
12               // 造緩衝流
13               BufferedReader br = new BufferedReader(fr);
14               BufferedWriter bw = new BufferedWriter(fw);) {
15 
16             // 使用char[]陣列
17             char[] cbuf = new char[1024];
18             int len;
19             while ((len = br.read(cbuf)) != -1) {
20                 bw.write(cbuf, 0, len);
21             }
22 
23             // bw.flush();
24         } catch (Exception e) {
25         }
26     }
27 }
28 
29 
30 // 方式二:不會自動換行
31 public class Main {
32 
33     public static void main(String[] args) {
34         try ( // 造節點流
35               FileReader fr = new FileReader(new File("F:\\hello.txt"));
36               FileWriter fw = new FileWriter(new File("F:\\hello_1.txt"));
37 
38               // 造緩衝流
39               BufferedReader br = new BufferedReader(fr);
40               BufferedWriter bw = new BufferedWriter(fw);) {
41 
42             // 使用readLine(),一次性讀一行
43             String data;
44             while ((data = br.readLine()) != null) {
45                 // data中不包含換行符,讀一行寫一行,不會自動換行.若想換行,可以:
46                 // 方法一:
47                 // bw.write(data + "\n");
48 
49                 // 方法二:
50                 bw.write(data);
51                 bw.newLine();
52             }
53 
54             // bw.flush();
55         } catch (Exception e) {
56         }
57     }
58 }

4、裝飾設計模式

  自定義的字元讀取流緩衝區myReadLine(),將readLine()方法實現了一次。
  程式碼示例:

 1 class MyBufferedReader {
 2     private final FileReader fileReader;
 3 
 4     public MyBufferedReader(FileReader fileReader) {
 5         this.fileReader = fileReader;
 6     }
 7 
 8     public String myReadLine() throws IOException {
 9         StringBuilder builder = new StringBuilder();
10 
11         int len;
12         while ((len = fileReader.read()) != -1) {
13             if (len == '\r') {
14                 continue;
15             }
16             if (len == '\n') {
17                 return builder.toString();
18             }
19 
20             builder.append((char) len);
21         }
22 
23         if (builder.length() != 0) {
24             return builder.toString();
25         }
26 
27         return null;
28     }
29 
30     public void myClose() {
31         try {
32             fileReader.close();
33         } catch (IOException e) {
34             e.printStackTrace();
35         }
36     }
37 }
38 
39 // 注意關閉資源
40 // 檔案:F:\\hello1.txt
41 // 內容:
42 我有a dream!
43 you need to have a dream!我有a dream!
44 you need to have a dream!
45 public class Main {
46     public static void main(String[] args) throws Exception {
47         MyBufferedReader reader = new MyBufferedReader(new FileReader(new File("F:\\hello1.txt")));
48 
49         String temp;
50         while ((temp = reader.myReadLine()) != null) {
51             System.out.println(temp);
52         }
53 
54         reader.myClose();
55     }
56 }
57 
58 // 結果.列印正常

五、轉換流

1、介紹

  轉換流提供了在位元組流和字元流之間的轉換。
  InputStreamReader:將InputStream轉換為Reader,實現將位元組的輸入流按指定字符集轉換為字元的輸入流。解碼。
  OutputStreamWriter:將Writer轉換為OutputStream,實現將字元的輸出流按指定字符集轉換為位元組的輸出流。編碼。
  很多時候使用轉換流來處理檔案亂碼問題。實現編和解碼的功能。

2、InputStreamReader

  每次呼叫InputStreamReader中的一個read()方法都會導致從底層輸入流讀取一個或多個位元組。要啟用從位元組到字元的有效轉換,可以提前從底層流讀取更多的位元組,使其超過滿足當前讀取操作所需的位元組。
  為了達到最高效率,可要考慮在InputStreamReader外套接一層BufferedReader。
  鍵盤錄入的標準寫法:BufferedReader in = new BufferedReader(new InputStreamReader(System.in))
  程式碼示例:讀檔案。位元組流->字元流

 1 public class Main {
 2 
 3     public static void main(String[] args) {
 4         try (FileInputStream fis = new FileInputStream(new File("F:\\hello.txt"));
 5              InputStreamReader isr = new InputStreamReader(fis, "UTF-8");) {
 6 
 7             char[] cbuf = new char[1024];
 8             int len;
 9             while ((len = isr.read(cbuf)) != -1) {
10                 String str = new String(cbuf, 0, len);
11                 System.out.print(str);
12             }
13 
14         } catch (Exception e) {
15         }
16     }
17 }

  程式碼示例:讀鍵盤。緩衝流

 1 public class Main {
 2 
 3     public static void main(String[] args) {
 4         try (// 從標準鍵盤輸入.
 5              BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));) {
 6 
 7             String line = null;
 8             while ((line = reader.readLine()) != null) {
 9                 if ("over".equals(line)) {
10                     return;
11                 }
12                 System.out.println(line);
13             }
14         } catch (Exception e) {
15         }
16     }
17 }

3、OutputStreamWriter

  每次呼叫write()方法都會導致在給定字元(或字符集)上呼叫編碼轉換器。在寫入底層輸出流之前,得到的這些位元組將在緩衝區中累積。可以指定此緩衝區的大小,不過,預設的緩衝區對數用途來說已足夠大。注意,傳遞給write()方法的字元沒有緩衝。
  為了獲得最高效率,可考慮在OutputStreamWriter外套接一層BufferedWriter。以避免頻繁呼叫轉換器。例:
  Writer out = new BufferedWriter(new OutputStreamWriter(System.out))
  程式碼示例:寫檔案。字元流->位元組流

 1 public class Main {
 2 
 3     public static void main(String[] args) {
 4         try (FileInputStream fis = new FileInputStream(new File("F:\\hello.txt"));
 5              FileOutputStream fos = new FileOutputStream(new File("F:\\hello_1.txt"));
 6 
 7              InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
 8              OutputStreamWriter osw = new OutputStreamWriter(fos, "gbk");) {
 9 
10             char[] cbuf = new char[1024];
11             int len;
12             while ((len = isr.read(cbuf)) != -1) {
13                 osw.write(cbuf, 0, len);
14             }
15 
16             isr.close();
17             osw.close();
18         } catch (Exception e) {
19         }
20     }
21 }

  程式碼示例:讀\寫鍵盤。緩衝流

 1 public class Main {
 2 
 3     public static void main(String[] args) {
 4         try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
 5              BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));) {
 6 
 7             String line = null;
 8             while ((line = reader.readLine()) != null) {
 9                 if ("over".equalsIgnoreCase(line)) {
10                     break;
11                 }
12                 writer.write(line.toUpperCase());
13                 writer.newLine(); // 換行
14                 writer.flush();
15             }
16 
17             reader.close();
18             writer.close();
19         } catch (Exception e) {
20         }
21     }
22 }

4、字符集

  ASCII:美國標準資訊交換碼。用一個位元組的7位可以表示。
  ISO8859-1:拉丁碼錶。歐洲碼錶。用一個位元組的8位表示。
  GB2312:中國的中文編碼表。最多兩個位元組編碼所有字元
  GBK:中國的中文編碼表升級,融合了更多的中文文字元號。最多兩個位元組編碼
  Unicode:國際標準碼,融合了目前人類使用的所有字元。為每個字元分配唯一的字元碼。所有的文字都用兩個位元組來表示。
  UTF-8:變長的編碼方式,可用1-4個位元組來表示一個字元。

相關文章