IO流----轉換流、緩衝流
開啟一個文字檔案,另存為:
Ansi就是系統預設編碼(就是gbk)
建一個編碼是utf-8的txt檔案,
例:
import java.io.FileWriter; import java.io.IOException; public class Demo01 { public static void main(String[] args) throws IOException { //確定目的地 FileWriter fw=new FileWriter("E:\\zyx\\java\\utf-8.txt",true); //寫入目的地 fw.write("你好"); //釋放資源 fw.close(); } }
所以字元流無法實現utf-8編碼格式檔案的讀和寫。
如果需要指定編碼和緩衝區大小時,可以在位元組流的基礎上,構造一個InputStreamReader或者OutputStreamWriter。
1 OutputStreamWriter類
OutputStreamWriter 是字元流通向位元組流的橋樑:可使用指定的字元編碼表,將要寫入流中的字元編碼成位元組。它的作用的就是,將字串按照指定的編碼表轉成位元組,在使用位元組流將這些位元組寫出去。
1.1繼承體系
1.2原理
在OutputStreamWriter流中維護自己的緩衝區,當呼叫OutputStreamWriter物件的write方法時,會拿著字元到指定的碼錶中進行查詢,把查到的字元編碼值轉成位元組數存放到OutputStreamWriter緩衝區中。然後再呼叫重新整理功能,或者關閉流,或者緩衝區存滿後會把緩衝區中的位元組資料使用位元組流寫到指定的檔案中。
1.3構造方法
只支援utf-8和gbk這兩個碼錶
OutputStreamWriter是一個字元流,所以字元流的方法都能用
例:
import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; public class Demo02 { public static void main(String[] args) throws IOException { //指定目的地 FileOutputStream fos=new FileOutputStream("E:\\zyx\\java\\utf-8.txt",true); //續寫 //建立轉換流 OutputStreamWriter osw=new OutputStreamWriter(fos,"utf-8"); //寫入 osw.write("你好你好"); //重新整理資料 osw.flush(); //釋放資源:(new了誰關誰,先開的先關) osw.close(); fos.close(); } }
注意:釋放資源時,new了誰關誰,先開的後關
gbk例子:
import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; public class Demo03 { public static void main(String[] args) throws IOException { //指定目的地 FileOutputStream fos=new FileOutputStream("E:\\zyx\\java\\gbk.txt",true); //續寫 //建立轉換流 OutputStreamWriter osw=new OutputStreamWriter(fos,"gbk"); //寫入 osw.write("你好,java"); //osw.flush(); //釋放資源 osw.close(); fos.close(); } }
注意:gbk和utf-8不區分大小寫,可以寫成GBK
2 InputStreamReader類
utf-8是三個位元組代表一個漢字,直接用Filereader不能讀
InputStreamReader 是位元組流通向字元流的橋樑:它使用指定的字元編碼表讀取位元組並將其解碼為字元。它使用的字符集可以由名稱指定或顯式給定,或者可以接受平臺預設的字符集。
2.1繼承體系
2.2構造方法
例:
import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; public class Demo04 { public static void main(String[] args) throws IOException { //獲取資料來源 FileInputStream fis=new FileInputStream("E:\\zyx\\java\\utf-8.txt"); //建立轉換流 InputStreamReader isr=new InputStreamReader(fis,"utf-8"); //開始讀取 int len=0; while((len=isr.read())!=-1){ System.out.print((char)len); } //釋放資源 isr.close(); fis.close(); } }
改成gbk是這樣:
用字元陣列讀gbk的檔案
import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; public class Demo05 { public static void main(String[] args) throws IOException { FileInputStream fis=new FileInputStream("E:\\zyx\\java\\gbk.txt"); InputStreamReader isr=new InputStreamReader(fis); char[] ch=new char[24]; int len=0; while((len=isr.read(ch))!=-1){ System.out.print(new String(ch,0,len)); } isr.close(); fis.close(); } }
3 轉換流和子類區別
發現有如下繼承關係:
OutputStreamWriter:
|--FileWriter:
InputStreamReader:
|--FileReader;
父類和子類的功能的區別:
1)OutputStreamWriter和InputStreamReader是字元和位元組的橋樑:也可以稱之為字元轉換流。字元轉換流原理:位元組流+編碼表。
2)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");
這三句程式碼的功能是一樣的,其中第三句最為便捷。
3)一旦要指定其他編碼時,絕對不能用子類,必須使用字元轉換流。
4)用子類的條件:
1、操作的是檔案。2、使用預設編碼。
總結:
位元組--->字元 : 看不懂的--->看的懂的。 需要讀。輸入流。 InputStreamReader
字元--->位元組 : 看的懂的--->看不懂的。 需要寫。輸出流。 OutputStreamWriter
4緩衝流
讀取資料量大的檔案時,讀取的速度會很慢,很影響程式的效率。
Java中提高了一套緩衝流,它的存在,可提高IO流的讀寫速度。
緩衝流,根據流的分類分類位元組緩衝流與字元緩衝流。
4.1位元組緩衝流
位元組緩衝流根據流的方向,共有2個
寫入資料到流中,位元組緩衝輸出流 BufferedOutputStream
讀取流中的資料,位元組緩衝輸入流 BufferedInputStream
它們的內部都包含了一個緩衝區,通過緩衝區讀寫,就可以提高了IO流的讀寫速度
緩衝區就是一個容器
4.1.1構造方法
例:
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class Demo06 { public static void main(String[] args) throws IOException { method02(); } //位元組輸出緩衝流 public static void method01() throws IOException{ //明確目的地 FileOutputStream fos=new FileOutputStream("E:\\zyx\\java\\demo.txt"); //加緩衝流 BufferedOutputStream bos=new BufferedOutputStream(fos); bos.write(100); bos.close(); //fos.close(); //可以不加,bos會自動關上fos } //位元組輸入緩衝流 public static void method02() throws IOException{ //明確資料來源 FileInputStream fis=new FileInputStream("E:\\zyx\\java\\demo.txt"); //加緩衝流 BufferedInputStream bis=new BufferedInputStream(fis); int len=0; while((len=bis.read())!=-1){ System.out.println((char)len); } bis.close(); } }
4.1.2複製比較示例
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; public class Demo07 { public static void main(String[] args) throws IOException { copy02(); } //單個位元組檔案複製 public static void copy01() throws IOException{ //明確資料來源 FileInputStream fis=new FileInputStream("E:\\zyx\\java\\tomcat.zip"); //明確目的地 FileOutputStream fos=new FileOutputStream("E:\\zyx\\java\\a\\tomcat.zip"); //開始複製 long time1=System.currentTimeMillis(); int len=0; while((len=fis.read())!=-1){ fos.write(len); } long time2=System.currentTimeMillis(); System.out.println(time2-time1); fis.close(); fos.close(); } //單個位元組,位元組緩衝流複製 public static void copy02() throws IOException{ //明確資料來源 FileInputStream fis=new FileInputStream("E:\\zyx\\java\\tomcat.zip"); BufferedInputStream bis=new BufferedInputStream(fis); //明確目的地 FileOutputStream fos=new FileOutputStream("E:\\zyx\\java\\a\\tomcat.zip"); BufferedOutputStream bos=new BufferedOutputStream(fos); //開始複製 long time1=System.currentTimeMillis(); int len=0; while((len=bis.read())!=-1){ bos.write(len); } long time2=System.currentTimeMillis(); System.out.println(time2-time1); bis.close(); bos.close(); //System.out.println(system.in); } }
copy01()結果:
copy02()結果:
4.1.3用位元組陣列方式複製的比較
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class CopyTest { public static void main(String[] args) throws IOException { copy01(); } //普通流複製 public static void copy01() throws IOException{ //指定資料來源 FileInputStream fis=new FileInputStream("E:\\zyx\\java\\eclipse.zip"); //指定目的地 FileOutputStream fos=new FileOutputStream("E:\\zyx\\java\\e\\eclipse.zip"); //複製 long start=System.currentTimeMillis(); int len=0; byte[] bys=new byte[1024]; while((len=fis.read(bys))!=-1){ fos.write(bys); } long end=System.currentTimeMillis(); System.out.println(end-start); fis.close(); fos.close(); } //緩衝流複製 public static void copy02() throws IOException{ //指定資料來源 FileInputStream fis=new FileInputStream("E:\\zyx\\java\\eclipse.zip"); BufferedInputStream bis=new BufferedInputStream(fis); //指定目的地 FileOutputStream fos=new FileOutputStream("E:\\zyx\\java\\f\\eclipse.zip"); BufferedOutputStream bos=new BufferedOutputStream(fos); long start=System.currentTimeMillis(); int len=0; byte[] bys=new byte[1024]; while((len=bis.read(bys))!=-1){ bos.write(bys); } long end=System.currentTimeMillis(); System.out.println(end-start); bis.close(); bos.close(); } }
結果比較:
5字元緩衝流
字元緩衝輸入流 BufferedReader
字元緩衝輸出流 BufferedWriter
完成文字資料的高效的寫入與讀取的操作
5.1 BufferedWriter
\r\n換行:
import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; public class Test { public static void main(String[] args) throws IOException { //明確日的地 FileWriter fw=new FileWriter("E:\\zyx\\java\\demo01.txt"); //新增緩衝流 BufferedWriter bw=new BufferedWriter(fw); //會自動關閉fw //寫入檔案 bw.write("你好\r\n"); bw.flush(); fw.write("java\r\n"); bw.flush(); bw.write("中國\r\n"); bw.close(); //會自動關閉fw } }
newLine() 方法:
import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; public class Test { public static void main(String[] args) throws IOException { //明確日的地 FileWriter fw=new FileWriter("E:\\zyx\\java\\demo01.txt"); //新增緩衝流 BufferedWriter bw=new BufferedWriter(fw); //會自動關閉fw //寫入檔案 bw.write("你好"); bw.newLine(); bw.flush(); fw.write("java"); bw.newLine(); bw.flush(); bw.write("中國"); bw.newLine(); bw.close(); //會自動關閉fw } }
Tips:
\r\n是windows的換行
Linux是\n
5.2字元緩衝輸入流 BufferedReader
方法public String readLine() 讀取一個文字行,包含該行內容的字串,不包含任何行終止符,如果已到達流末尾,則返回null
例:
import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; public class Test { public static void main(String[] args) throws IOException { // 明確資料來源 FileReader fr = new FileReader("E:\\zyx\\java\\demo01.txt"); // 新增緩衝流 BufferedReader br = new BufferedReader(fr); // 讀取 String line = ""; int lineNum = 0; // 加個行號 while ((line = br.readLine()) != null) { lineNum++; System.out.println(lineNum + " " + line); } fr.close(); } }
Tips:
readLine()不會把換行符讀出來
可以手動加一個行號
5.3複製文字檔案比較
6流的操作規律
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