IO流
1. IO流:用於處理設備上的數據。
設備:硬盤,內存,鍵盤錄入。
2. IO有具體的分類:
(1)根據處理的數據類型不同:字節流和字符流。
(2)根據流向不同:輸入流和輸出流。
字符流的由來:
因為文件編碼的不同,而有了對字符進行高效操作的字符流對象。
原理:其實就是基於字節流讀取字節時,去查了指定的碼表。
字節流和字符流的區別:
(1)字節流讀取的時候,讀到一個字節就返回一個字節。
字符流使用了字節流讀到一個或多個字節(中文對應的字節數是兩個,在UTF-8碼表中是3個字節)時,先去查指定的編碼表,將查到的字符返回。
(2)字節流可以處理所有類型數據,如MP3,圖片,avi。而字符流只能處理字符數據。
結論:只要是處理純文本數據,就要優先考慮使用字符流,除此之外都要用字節流。
IO的體系,所具備的基本功能就有兩個:讀和寫。
1.字節流:InputStream(讀),OutputStream(寫)。
2.字符流:Reader(讀),Writer(寫)。
一.字符流:
Reader
|--InputStreamReader
|--FileReader:專門用於處理文件的字符讀取流對象。
Writer
|--OutputStreamWriter
|--FileWriter:專門用於處理文件的字符寫入流對象
Reader中的常見的方法:
1. int read():
讀取一個字符。返回的是讀到的那個字符。如果讀到流的末尾,返回-1.
2. int read(char[]):
將讀到的字符存入指定的數組中,返回的是讀到的字符個數,也就是往數組里裝的元素的個數。如果讀到流的末尾,返回-1.
3. close():
讀取字符其實用的是window系統的功能,就希望使用完畢后,進行資源的釋放。
Writer中的常見的方法:
1,write(ch): 將一個字符寫入到流中。
2,write(char[]): 將一個字符數組寫入到流中。
3,write(String): 將一個字符串寫入到流中。
4,flush():刷新流,將流中的數據刷新到目的地中,流還存在。
5,close():關閉資源:在關閉前會先調用flush(),刷新流中的數據去目的地。然流關閉。
FileWriter:
該類沒有特有的方法。只有自己的構造函數。
該類特點在於,
1,用於處理文本文件。
2,該類中有默認的編碼表,
3,該類中有臨時緩沖。
構造函數:在寫入流對象初始化時,必須要有一個存儲數據的目的地。
FileWriter(String filename): 該構造函數做了什么事情呢?
1,調用系統資源。
2,在指定位置,創建一個文件。
注意:如果該文件已存在,將會被覆蓋。
FileWriter(String filename,boolean append):
該構造函數:當傳入的boolean類型值為true時,會在指定文件末尾處進行數據的續寫。
FileReader:
1,用於讀取文本文件的流對象。
2,用於關聯文本文件。
構造函數:在讀取流對象初始化的時候,必須要指定一個被讀取的文件。
如果該文件不存在會發生FileNotFoundException.
FileReader(String filename);
對於讀取或者寫入流對象的構造函數,以及讀寫方法,還有刷新關閉功能都會拋出IOException或其子類。
所以都要進行處理,或者throws拋出,或者try、catch處理。
將文本數據存儲到一個文件:
1 import java.io.*; 2 public class TestFileWriter1 { 3 public static void main(String[] args){ 4 FileWriter fw=null; 5 try{ 6 fw=new FileWriter("D:\\JAVA練習代碼\\123.txt"); 7 fw.write("abcdec"); 8 fw.flush(); 9 fw.write("kkkk"); 10 }catch(IOException e){ 11 System.out.println(e.toString()); 12 } 13 finally{ 14 if(fw!=null) 15 try{ 16 fw.close(); 17 }catch (IOException e) { 18 System.out.println("close"+e.toString()); 19 } 20 } 21 } 22 }
另一個小細節:
當指定絕對路徑時,定義目錄分隔符有兩種方式:
1,反斜線 但是一定要寫兩個。\\ new FileWriter("c:\\demo.txt");
2,斜線 / 寫一個即可。 new FileWriter("c:/demo.txt");
讀一個字符就存入字符數組里,讀完1Kb再打印。
1 import java.io.*; 2 public class TestFileReader1 { 3 public static void main(String[] args){ 4 FileReader fr=null; 5 try{ 6 fr=new FileReader("D:\\JAVA練習代碼\\abc.txt"); 7 char[]buf=new char[1024]; //該長度通常都是1024的整數倍 8 int len=0; 9 while((len=fr.read(buf))!=-1){ 10 System.out.println(new String(buf,0,len)); 11 } 12 }catch(IOException e){ 13 System.out.println(e); 14 } 15 finally{ 16 if(fr!=null){ 17 try{ 18 fr.close(); 19 }catch(IOException e){ 20 System.out.println("close"+e); 21 } 22 } 23 } 24 } 25 }
字符流的緩沖區:
緩沖區的出現提高了對流的操作效率。
原理:其實就是將數組進行封裝。
對應的對象:
BufferedWriter:
特有方法:
newLine():跨平台的換行符。
BufferedReader:
特有方法:
readLine():一次讀一行,到行標記時,將行標記之前的字符數據作為字符串返回。當讀到末尾時,返回null。
使用緩沖區對象時,要明確,緩沖的存在是為了增強流的功能而存在,所以在簡歷緩沖區對象時,要現有流對象存在。
其實緩沖內部就是在使用流對象的方法,只不過加入了數組對數據進行了臨時存儲,為了提高操作數據的效率。
代碼上的體現:
寫入緩沖區對象:
//建立緩沖區對象必須把流對象作為參數傳遞給緩沖區的構造函數。
BufferedWriter bw=new BufferedWriter(new FileWriter(“abc.txt”));
bw.write("abce");//將數據寫入到了緩沖區。
bw.flush();//對緩沖區的數據進行刷新。將數據刷到目的地中。
bw.close();//關閉緩沖區,其實關閉的是被包裝在內部的流對象。
讀取緩沖區對象:
BufferedReader br=new BufferedReader(new FileReader("abc.txt"));
String s=null;
1 import java.io.*; 2 public class TestBufferStream { 3 public static void main(String[] args){ 4 try{ 5 BufferedWriter bw=new BufferedWriter(new FileWriter("D:\\Java練習代碼\\abc.txt")); 6 BufferedReader br=new BufferedReader(new FileReader("D:\\Java練習代碼\\abc.txt")); 7 String s=null; 8 for(int i=1;i<=100;i++){ 9 s=String.valueOf(Math.random()); 10 bw.write(s); 11 bw.newLine(); 12 } 13 bw.flush(); 14 while((s=br.readLine())!=null){ 15 System.out.println(s); 16 } 17 bw.close(); 18 br.close(); 19 }catch (IOException e){ 20 e.printStackTrace(); 21 } 22 } 23 }
二.字節流:
抽象基類:InputStream,OutputStream。
字節流可以操作任何數據。
注意:字符流使用的數組是字符數組,char[] chs ;
字節流使用的數組是字節數組,byte[] bt ;
FileOutputStream fos=new FileOutputStream(“a.txt”);
fos.write("abcde"); //直接將數據寫入到了目的地。
fos.close();//只關閉資源。
FileInputSteam fls=new FileInputStream("a.txt");
//fis.available();//獲取關聯的文件字節數。如果文件體積不大,可以這樣操作。
byte[]buf=new byte[fis.available()];//創建一個剛剛好的緩沖區。//但是這有一個弊端,就是文件過大,大小超出Jvm的內容空間時,會內存溢出。
fis.read(buf);
System.out.println(new String(buf));
例子:
需求:copy一個圖片。
BufferedInputStream bufis=new BufferedInputStream(new FileInputStream("1.jpg"));
BufferedOutputStream bufos=new BufferedOutputStream(new FileOutputStream("2.jpg"));
int by=0;
while(by=bufis.read()!=-1){
bufos.write(by);
bufos.newLine();
}
bufis.close();
bufos.close();
小結:
目前學習的流對象:
字符流: FileReader FileWriter BuffereedReader BufferedWriter
字節流:FileInputStream FileOutputStream BufferedInputStream BufferedOutputStream
補充:
1.字節流的read()方法讀取的是一個字節。為什么返回的不是byte類型,而是int類型呢?
因為read方法讀到末尾時返回的是-1,而在所操作的數據中很容易出現連續多個1的情況,而連續讀到8個1,就是-1,導致讀取會提前停止。所以將讀到的一個字節提升為一個int類型的數值,但是只保留原字節,並在剩余二進制位補0。
具體操作是:byte&255 or byte&0xff
2.對於write方法,可以一次寫入一個字節,但接收的是一個int類型數值。只寫入該int類型的數值的最低一個字節(8位)。
簡單說:read方法對讀到的數據進行提升,write對操作的數據進行轉換。
