IO流的分類
-
根據處理數據類型的不同分爲:字符流和字節流
-
根據數據流向不同分爲:輸入流和輸出流
進行輸入、輸出操作一般都會按照如下步驟進行:
- 通過File類定義一個要操作文件的路徑
- 通過字節流或字符流的子類對象爲父類對象實例化
- 進行數據的讀(輸入)、寫(輸出)操作
- 數據流屬於資源操作,資源操作必須關閉
java.io包定義了兩類流:
- 字節流(JDK 1.0):InputStream、OutputStream
- 字符流(JDK 1.1):Writer、Reader
1. 字節流
1.1 字節輸出流(OutputStream)
OutputStream這個抽象類是表示字節輸出流的所有類的超類。
輸出流接收輸出字節並將其發送到某個接收器。
需要定義OutputStream子類的應用OutputStream必須至少提供一個寫入一個字節輸出的方法。
OutputStream類提供了三個輸出的方法:
- 輸出單個字節:public abstract void write(int b)
- 輸出全部字節數組:public void write(byte[] b)
- 輸出部分字節數組:public void write(byte[] b,int off,int len)
OutputStream本身屬於抽象類,如果想爲抽象類進行對象的實例化操作,需要使用抽象類的子類,進行文件操作可以使用FileOutputStream子類。在這個子類中定義瞭如下構造方法:
- FileOutputStream(File file) 創建文件輸出流以寫入由指定的File對象表示的文件
- FileOutputStream(File file, boolean append) 文件內容追加
使用全部字節數組進行輸出示例:
//1. 定義要輸出的文件路徑
File file = new File("E:"+File.separator+"demo"+File.separator+"test.txt");
//如果目錄不存在則先創建目錄
if(file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
//2. 應該使用OutputStream和其子類進行對象的實例化,此時目錄存在,文件還不存在
OutputStream outputStream = new FileOutputStream(file);
//3. 進行文件內容的輸出
String str = "好好學習,天天向上";
//將字符串轉爲byte數組
byte[] data = str.getBytes();
outputStream.write(data);
//4. 關閉資源
outputStream.close();
使用部分字節數組輸出示例
//1. 定義要輸出的文件路徑
File file = new File("E:"+File.separator+"demo"+File.separator+"study.txt");
//如果目錄不存在則先創建目錄
if(file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
//2. 應該使用OutputStream和其子類進行對象的實例化,此時目錄存在,文件還不存在
OutputStream outputStream = new FileOutputStream(file);
//3. 進行文件內容的輸出
String str = "我們要好好學習技術,然後找個好工作,多賺點錢,補貼家用,實現自我價值,成爲一個對社會有用的人";
//將字符串轉爲byte數組
byte[] data = str.getBytes();
outputStream.write(data,0,6);
//4. 關閉資源
outputStream.close();
1.2 字節輸入流:InputStream
InputStream抽象類是表示輸入字節流的所有類的超類。
需要定義InputStream子類的應用InputStream必須始終提供一種返回輸入的下一個字節的方法。
InputSream提供了三個輸入的方法:
- public abstract int read() 從輸入流讀取數據的下一個字節
- public int read(byte[] b) 從輸入流讀取一些字節數,並將它們存儲到緩衝區b 。 實際讀取的字節數作爲整數返回。 該方法阻塞直到輸入數據可用,檢測到文件結束或拋出異常。
- public int read(byte[] b,int off,int len) 從輸入流讀取len字節的數據到一個字節數組。 嘗試讀取多達len個字節,但可以讀取較小的數字。 實際讀取的字節數作爲整數返回。該方法阻塞直到輸入數據可用,檢測到文件結束或拋出異常。
使用FileInputStream讀入文件示例
//1. 定義要輸入的文件路徑
File file = new File("E:"+File.separator+"demo"+File.separator+"study.txt");
//判斷文件是否存在後纔可以進行讀取
if(file.exists()){
// 2. 使用FileInputStream進行讀取
InputStream inputStream = new FileInputStream(file);
//準備處理一個1024的數組
byte[] data = new byte[1024];
//字節數組的操作腳標
int foot = 0;
//表示每次讀取的字節數據
int temp = 0;
//讀取一個字節
while((temp = inputStream.read()) != -1){
if(temp != -1){
data[foot++] = (byte)temp;
}
}
//4. 關閉流
inputStream.close();
System.out.println("["+new String(data,0,foot)+"]");
}
}
2. 字符流
2.1 字符輸出流:Writer
Writer是用於寫入字符流的抽象類。子類必須實現的唯一方法是write(char [],int,int),flush()和close()。 然而,大多數子類將覆蓋這裏定義的一些方法,以便提供更高的效率,或者附加功能。
Writer提供的常用方法
- write(char[] cbuf) 寫入一個字符數組。
- write(char[] cbuf, int off, int len) 寫入字符數組的一部分。
- write(int c) 寫一個字符
- write(String str) 寫一個字符串
- write(String str, int off, int len) 寫一個字符串的一部分。
- append(char c) 附加指定的字符
- close() 關閉流,先刷新。
- flush() 刷新流。
使用字符輸出流輸出字符串示例
//1. 定義要輸出的文件路徑
File file = new File("E:"+File.separator+"demo"+File.separator+"writer.txt");
//如果目錄不存在則創建
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
//2. 實例化Writer類對象
Writer out = new FileWriter(file);
//3. 進行內容輸出
String str = "好好學習,天天向上!!!";
//輸出字符串數據
out.write(str);
//4. 關閉流
out.close();
2.2 字符輸入流:Reader
用於讀取字符流的抽象類。 子類必須實現的唯一方法是read(char [],int,int)和close()。 然而,大多數子類將覆蓋這裏定義的一些方法,以便提供更高的效率以及附加的功能。
Reader提供的常用方法
- read() 讀一個字符
- read(char[] cbuf) 將字符讀入數組。
- read(char[] cbuf, int off, int len) 將字符讀入數組的一部分。
- read(CharBuffer target) 嘗試將字符讀入指定的字符緩衝區。
- ready() 告訴這個流是否準備好被讀取。
- close() 關閉流並釋放與之相關聯的任何系統資源。
- mark(int readAheadLimit) 標記流中的當前位置。
- reset() 重置流。
讀入文件可以使用子類FileReader,示例代碼如下:
//1. 定義要輸入的文件路徑
File file = new File("E:"+File.separator+"demo"+File.separator+"writer.txt");
//判斷文件是否存在後纔可以進行讀取
if(file.exists()){
// 2. 爲Reader類對象實例化
Reader input = new FileReader(file);
// 3. 進行數據讀取
char[] c = new char[1024];
int len = input.read(c);
//4. 關閉流
input.close();
System.out.println(new String(c,0,len));
}
與字節輸入流相比結構幾乎一樣,只是數據類型由byte變爲char
3. 字節流與字符流的區別
- 字節流直接與終端進行數據交互,字符流需要將數據經過緩存區處理後纔可以輸出
- 讀寫單位不同:字節流以字節(8bit)爲單位,字符流以字符爲單位,根據碼錶映射字符,一次可能讀多個字節。
- 字節流處理二進制數據,字符流處理文本文件
- 字節流可以轉爲字符流,而字符流不能轉爲字節流
- 進行中文處理時優先考慮字符流
4. 字節流轉換爲字符流
在java.io包裏面提供了兩個類:InputStreamReader和OutputStreamWriter用於將字節流轉爲字符流
名稱: | InputStreamReader | OutputStreamWriter |
---|---|---|
定義結構: | public class InputStreamReader extends Reader | InputStreamReader(InputStream in) |
構造方法: | public class OutputStreamWriter extends Writer | OutputStreamWriter(OutputStream out) |
InputStreamReader是將字節輸入流轉爲字符輸入流:它讀取字節,並使用指定的charset將其解碼爲字符。 它使用的字符集可以由名稱指定,也可以被明確指定,或者可以接受平臺的默認字符集。每個調用InputStreamReader的read()方法會導致從底層字節輸入流讀取一個或多個字節。 爲了使字節有效地轉換爲字符,可以從底層流讀取比滿足當前讀取操作所需的更多字節。
爲了最大的效率,請考慮在BufferedReader中包裝一個InputStreamReader。 例如:BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
OutputStreamWriter是將字節輸出流轉爲字符輸出流。 它使用的字符集可以由名稱指定,也可以被明確指定,或者可以接受平臺的默認字符集。
每次調用write()方法都會使編碼轉換器在給定字符上被調用。 所得到的字節在寫入底層輸出流之前累積在緩衝區中。 可以指定此緩衝區的大小。 請注意,傳遞給write()方法的字符不會緩衝。
爲了最大的效率,請考慮在BufferedWriter中包裝一個OutputStreamWriter,以避免頻繁的轉換器調用。 例如:Writer out = new BufferedWriter(new OutputStreamWriter(System.out));
將字節輸出流轉爲字符輸出流示例
File file = new File("E:"+ File.separator+"demo"+File.separator+"study.txt");
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
//字節流
OutputStream output = new FileOutputStream(file);
//將字節流轉換爲字符流
Writer out = new OutputStreamWriter(output);
String c = "Hello World!";
//進行輸出
out.write(c);
out.flush();
out.close();
將字節輸入流轉爲字符輸入流示例
File file = new File("E:"+ File.separator+"demo"+File.separator+"study.txt");
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
//字節輸入流
InputStream in = new FileInputStream(file);
//將字節輸入流轉爲字符輸入流
Reader input = new InputStreamReader(in);
char[] c = new char[1024];
//讀數據
input.read(c);
//關閉流
input.close();
System.out.println(new String(c));
- 兩個轉換類都是字符流的子類,屬於字符流與字節流溝通的橋樑