一、緩衝流
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個位元組來表示一個字元。