今日內容介紹
-
轉換流
-
緩衝流
1 轉換流
在學習字元流(FileReader、FileWriter)的時候,其中說如果需要指定編碼和緩衝區大小時,可以在位元組流的基礎上,構造一個InputStreamReader或者OutputStreamWriter,這又是什麼意思呢?
OutputStreamWriter類
查閱OutputStreamWriter的API介紹,OutputStreamWriter 是字元流通向位元組流的橋樑:可使用指定的字元編碼表,將要寫入流中的字元編碼成位元組。它的作用的就是,將字串按照指定的編碼表轉成位元組,在使用位元組流將這些位元組寫出去。
-
程式碼演示:
public static void writeCN() throws Exception { //建立與檔案關聯的位元組輸出流物件 FileOutputStream fos = new FileOutputStream("c:\\cn8.txt"); //建立可以把字元轉成位元組的轉換流物件,並指定編碼 OutputStreamWriter osw = new OutputStreamWriter(fos,"utf-8"); //呼叫轉換流,把文字寫出去,其實是寫到轉換流的緩衝區中 osw.write("你好");//寫入緩衝區。 osw.close(); }
OutputStreamWriter流物件,它到底如何把字元轉成位元組輸出的呢?
其實在OutputStreamWriter流中維護自己的緩衝區,當我們呼叫OutputStreamWriter物件的write方法時,會拿著字元到指定的碼錶中進行查詢,把查到的字元編碼值轉成位元組數存放到OutputStreamWriter緩衝區中。然後再呼叫重新整理功能,或者關閉流,或者緩衝區存滿後會把緩衝區中的位元組資料使用位元組流寫到指定的檔案中。
InputStreamReader類
查閱InputStreamReader的API介紹,InputStreamReader 是位元組流通向字元流的橋樑:它使用指定的字元編碼表讀取位元組並將其解碼為字元。它使用的字符集可以由名稱指定或顯式給定,或者可以接受平臺預設的字符集。
-
程式碼演示
public class InputStreamReaderDemo { public static void main(String[] args) throws IOException { //演示位元組轉字元流的轉換流 readCN(); } public static void readCN() throws IOException{ //建立讀取檔案的位元組流物件 InputStream in = new FileInputStream("c:\\cn8.txt"); //建立轉換流物件 //InputStreamReader isr = new InputStreamReader(in);這樣建立物件,會用本地預設碼錶讀取,將會發生錯誤解碼的錯誤 InputStreamReader isr = new InputStreamReader(in,"utf-8"); //使用轉換流去讀位元組流中的位元組 int ch = 0; while((ch = isr.read())!=-1){ System.out.println((char)ch); } //關閉流 isr.close(); } }
注意:在讀取指定的編碼的檔案時,一定要指定編碼格式,否則就會發生解碼錯誤,而發生亂碼現象。
轉換流和子類區別
發現有如下繼承關係:
OutputStreamWriter:
|--FileWriter:
InputStreamReader:
|--FileReader;
父類和子類的功能有什麼區別呢?
OutputStreamWriter和InputStreamReader是字元和位元組的橋樑:也可以稱之為字元轉換流。字元轉換流原理:位元組流+編碼表。
FileWriter和FileReader:作為子類,僅作為操作字元檔案的便捷類存在。當操作的字元檔案,使用的是預設編碼表時可以不用父類,而直接用子類就完成操作了,簡化了程式碼。
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));//預設字符集。
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"GBK");//指定GBK字符集。
FileReader fr = new FileReader("a.txt");
這三句程式碼的功能是一樣的,其中第三句最為便捷。
注意:一旦要指定其他編碼時,絕對不能用子類,必須使用字元轉換流。什麼時候用子類呢?
條件:
1、操作的是檔案。2、使用預設編碼。
總結:
位元組--->字元 : 看不懂的--->看的懂的。 需要讀。輸入流。 InputStreamReader
字元--->位元組 : 看的懂的--->看不懂的。 需要寫。輸出流。 OutputStreamWriter
2 緩衝流
在我們學習位元組流與字元流的時候,大家都進行過讀取檔案中資料的操作,讀取資料量大的檔案時,讀取的速度會很慢,很影響我們程式的效率,那麼,我想提高速度,怎麼辦?
Java中提高了一套緩衝流,它的存在,可提高IO流的讀寫速度
緩衝流,根據流的分類分類位元組緩衝流與字元緩衝流。
位元組緩衝流
位元組緩衝流根據流的方向,共有2個
-
寫入資料到流中,位元組緩衝輸出流 BufferedOutputStream
-
讀取流中的資料,位元組緩衝輸入流 BufferedInputStream
它們的內部都包含了一個緩衝區,通過緩衝區讀寫,就可以提高了IO流的讀寫速度
位元組緩衝輸出流BufferedOutputStream
通過位元組緩衝流,進行檔案的讀寫操作 寫資料到檔案的操作
-
構造方法
public BufferedOutputStream(OutputStream out)建立一個新的緩衝輸出流,以將資料寫入指定的底層輸出流。
public class BufferedOutputStreamDemo01 { public static void main(String[] args) throws IOException { //寫資料到檔案的方法 write(); } /* * 寫資料到檔案的方法 * 1,建立流 * 2,寫資料 * 3,關閉流 */ private static void write() throws IOException { //建立基本的位元組輸出流 FileOutputStream fileOut = new FileOutputStream("abc.txt"); //使用高效的流,把基本的流進行封裝,實現速度的提升 BufferedOutputStream out = new BufferedOutputStream(fileOut); //2,寫資料 out.write("hello".getBytes()); //3,關閉流 out.close(); } }
位元組緩衝輸入流 BufferedInputStream
剛剛我們學習了輸出流實現了向檔案中寫資料的操作,那麼,現在我們完成讀取檔案中資料的操作
-
構造方法
public BufferedInputStream(InputStream in)
/* * 從檔案中讀取資料 * 1,建立緩衝流物件 * 2,讀資料,列印 * 3,關閉 */ private static void read() throws IOException { //1,建立緩衝流物件 FileInputStream fileIn = new FileInputStream("abc.txt"); //把基本的流包裝成高效的流 BufferedInputStream in = new BufferedInputStream(fileIn); //2,讀資料 int ch = -1; while ( (ch = in.read()) != -1 ) { //列印 System.out.print((char)ch); } //3,關閉 in.close(); }
使用基本的流與高效的流完成複製檔案
我們一直在說,高效的流速度快並高效,怎麼體現呢?需要通過一個複製檔案耗時的比較過程,來體驗一下高效流帶來的快感。
/* * 需求:將d:\\test.avi檔案進行復制 * 採用4種方式複製 * 方式1:採用基本的流,一次一個位元組的方式複製 共耗時 224613毫秒 * 方式2:採用基本的流,一個多個位元組的方式賦值 共耗時 327毫秒 * 方式3:採用高效的流,一次一個位元組的方式複製 共耗時 2047毫秒 * 方式4:採用高效的流,一個多個位元組的方式賦值 共耗時 96毫秒 * * 資料來源: d:\\test.avi * 目的地1: d:\\copy1.avi * 目的地2: d:\\copy2.avi * 目的地3: d:\\copy3.avi * 目的地4: d:\\copy4.avi * * 實現的步驟: * 1,指定資料來源 * 2,指定目的地 * 3,讀資料 * 4,寫資料 * 5,關閉流 * */ public class CopyAVI { public static void main(String[] args) throws IOException { //開始計時 long start = System.currentTimeMillis(); //方式1:採用基本的流,一次一個位元組的方式複製 //method1("d:\\test.avi", "d:\\copy1.avi"); //方式2:採用基本的流,一個多個位元組的方式賦值 //method2("d:\\test.avi", "d:\\copy2.avi"); //方式3:採用高效的流,一次一個位元組的方式複製 //method3("d:\\test.avi", "d:\\copy3.avi"); //方式4:採用高效的流,一個多個位元組的方式賦值 method4("d:\\test.avi", "d:\\copy4.avi"); //結束計時 long end = System.currentTimeMillis(); //列印耗時多少毫秒 System.out.println("共耗時 " +(end - start)+ "毫秒"); } //方式4:採用高效的流,一個多個位元組的方式賦值 private static void method4(String src, String dest) throws IOException { //1,指定資料來源 BufferedInputStream in = new BufferedInputStream(new FileInputStream(src)); //2,指定目的地 BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest)); //3,讀資料 byte[] buffer = new byte[1024]; int len = -1; while ( (len = in.read(buffer)) != -1) { //4,寫資料 out.write(buffer, 0, len); } //5,關閉流 in.close(); out.close(); } //方式3:採用高效的流,一次一個位元組的方式複製 private static void method3(String src, String dest) throws IOException { //1,指定資料來源 BufferedInputStream in = new BufferedInputStream(new FileInputStream(src)); //2,指定目的地 BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest)); //3,讀資料 int ch = -1; while ((ch=in.read()) != -1) { //4,寫資料 out.write(ch); } //5,關閉流 in.close(); out.close(); } //方式2:採用基本的流,一個多個位元組的方式賦值 private static void method2(String src, String dest) throws IOException { //1,指定資料來源 FileInputStream in = new FileInputStream(src); //2,指定目的地 FileOutputStream out = new FileOutputStream(dest); //3,讀資料 byte[] buffer = new byte[1024]; int len = -1; while ( (len=in.read(buffer)) != -1) { //4,寫資料 out.write(buffer, 0, len); } //5,關閉流 in.close(); out.close(); } //方式1:採用基本的流,一次一個位元組的方式複製 private static void method1(String src, String dest) throws IOException { //1,指定資料來源 FileInputStream in = new FileInputStream(src); //2,指定目的地 FileOutputStream out = new FileOutputStream(dest); //3,讀資料 int ch = -1; while (( ch=in.read()) != -1) { //4,寫資料 out.write(ch); } //5,關閉流 in.close(); out.close(); } }
字元緩衝流
-
字元緩衝輸入流 BufferedReader
-
字元緩衝輸出流 BufferedWriter
完成文字資料的高效的寫入與讀取的操作
字元緩衝輸出流 BufferedWriter
將文字寫入字元輸出流,緩衝各個字元,從而提供單個字元、陣列和字串的高效寫入。
-
方法:
void newLine() 根據當前的系統,寫入一個換行符
/* * BufferedWriter 字元緩衝輸出流 * 方法 * public void newLine()寫入一個行分隔符 * * 需求:通過緩衝輸出流寫入資料到檔案 * 分析: * 1,建立流物件 * 2,寫資料 * 3,關閉流 * */ public class BufferedWriterDemo { public static void main(String[] args) throws IOException { //建立流 //基本字元輸出流 FileWriter fileOut = new FileWriter("file.txt"); //把基本的流進行包裝 BufferedWriter out = new BufferedWriter(fileOut); //2,寫資料 for (int i=0; i<5; i++) { out.write("hello"); out.newLine(); } //3,關閉流 out.close(); } }
字元緩衝輸入流 BufferedReader
從字元輸入流中讀取文字,緩衝各個字元,從而實現字元、陣列和行的高效讀取。
-
方法
public String readLine() 讀取一個文字行,包含該行內容的字串,不包含任何行終止符,如果已到達流末尾,則返回 null
/* * BufferedReader 字元緩衝輸入流 * * 方法: * String readLine() * 需求:從檔案中讀取資料,並顯示資料 */ public class BufferedReaderDemo { public static void main(String[] args) throws IOException { //1,建立流 BufferedReader in = new BufferedReader(new FileReader("file.txt")); //2,讀資料 //一次一個字元 //一次一個字元陣列 //一次讀取文字中一行的字串內容 String line = null; while( (line = in.readLine()) != null ){ System.out.println(line); } //3,關閉流 in.close(); } }
使用字元緩衝流完成文字檔案的複製
剛剛我們學習完了緩衝流,現在我們就使用字元緩衝流的特有功能,完成文字檔案的複製
/* * 採用高效的字元緩衝流,完成文字檔案的賦值 * * 資料來源: file.txt * 目的地: copyFile.txt * * 分析: * 1,指定資料來源,是資料來源中讀資料,採用輸入流 * 2,指定目的地,是把資料寫入目的地,採用輸出流 * 3,讀資料 * 4,寫資料 * 5,關閉流 */ public class CopyTextFile { public static void main(String[] args) throws IOException { //1,指定資料來源,是資料來源中讀資料,採用輸入流 BufferedReader in = new BufferedReader(new FileReader("file.txt")); //2,指定目的地,是把資料寫入目的地,採用輸出流 BufferedWriter out = new BufferedWriter(new FileWriter("copyFile.txt")); //3,讀資料 String line = null; while ( (line = in.readLine()) != null ) { //4,寫資料 out.write(line); //寫入換行符號 out.newLine(); } //5,關閉流 out.close(); in.close(); } }
流的操作規律
IO流中物件很多,解決問題(處理裝置上的資料時)到底該用哪個物件呢?
把IO流進行了規律的總結(四個明確):
-
明確一:要操作的資料是資料來源還是資料目的。
源:InputStream Reader
目的:OutputStream Writer
先根據需求明確要讀,還是要寫。
-
明確二:要操作的資料是位元組還是文字呢?
源:
位元組:InputStream
文字:Reader
目的:
位元組:OutputStream
文字:Writer
已經明確到了具體的體系上。
-
明確三:明確資料所在的具體裝置。
源裝置:
硬碟:檔案 File開頭。
記憶體:陣列,字串。
鍵盤:System.in;
網路:Socket
目的裝置:
硬碟:檔案 File開頭。
記憶體:陣列,字串。
螢幕:System.out
網路:Socket
完全可以明確具體要使用哪個流物件。
-
明確四:是否需要額外功能呢?
額外功能:
轉換嗎?轉換流。InputStreamReader OutputStreamWriter
高效嗎?緩衝區物件。BufferedXXX
InputStream
FileInputStream
BufferedInputStream
OuputStream
FileOutputStream
BufferedOuputStream
Writer
OutputStreamWriter
FileWriter
BufferedWriter
Reader
InputStreamReader
FileReader
BufferedReader
3 總結
知識點總結
-
位元組流
-
位元組輸入流 InputStream
-
FileInputStream 操作檔案的位元組輸入流
-
BufferedInputStream高效的位元組輸入流
-
-
位元組輸出流 OutputStream
-
FileOutputStream 操作檔案的位元組輸出流
-
BufferedOutputStream 高效的位元組輸出流
-
-
-
字元流
-
字元輸入流 Reader
-
FileReader 操作檔案的字元輸入流
-
BufferedReader 高效的字元輸入流
-
InputStreamReader 輸入操作的轉換流(把位元組流封裝成字元流)
-
-
字元輸出流 Writer
-
FileWriter 操作檔案的字元輸出流
-
BufferedWriter 高效的字元輸出流
-
OutputStreamWriter 輸出操作的轉換流(把位元組流封裝成字元流)
-
-
-
方法:
-
讀資料方法:
-
read() 一次讀一個位元組或字元的方法
-
read(byte[] char[]) 一次讀一個陣列資料的方法
-
readLine() 一次讀一行字串的方法(BufferedReader類特有方法)
-
readObject() 從流中讀取物件(ObjectInputStream特有方法)
-
-
寫資料方法:
-
write(int) 一次寫一個位元組或字元到檔案中
-
write(byte[] char[]) 一次寫一個陣列資料到檔案中
-
write(String) 一次寫一個字串內容到檔案中
-
writeObject(Object ) 寫物件到流中(ObjectOutputStream類特有方法)
-
newLine() 寫一個換行符號(BufferedWriter類特有方法)
-
-
-
向檔案中寫入資料的過程
1,建立輸出流物件
2,寫資料到檔案
3,關閉輸出流
-
從檔案中讀資料的過程
-
建立輸入流物件
-
從檔案中讀資料
-
關閉輸入流
-
檔案複製的過程
-
建立輸入流(資料來源)
-
建立輸出流(目的地)
-
從輸入流中讀資料
-
通過輸出流,把資料寫入目的地
-
關閉流