字節流與字符流的區別
字節流在操作的時候本身是不會用到緩衝區(內存)的,是與文件本身直接操作的,所以InputStream需要提前設置緩存區大小,而字符流在操作的時候是使用到緩衝區的。
字節流在操作文件時,即使不關閉資源(close方法),文件也能輸出,但是如果字符流不使用close方法的話,則不會輸出任何內容,說明字符流用的是緩衝區,並且可以使用flush方法強制進行刷新緩衝區,這時才能在不close的情況下輸出內容
那開發中究竟用字節流好還是用字符流好呢?
在所有的硬盤上保存文件或進行傳輸的時候都是以字節的方法進行的,包括圖片也是按字節完成,而字符是只有在內存中才會形成的,所以使用字節的操作是最多的。
Java IO
Java IO中用於讀寫文件的四個抽象類:Reader,Writer,InputStream,OutputStream。
根據流所處理的數據類型分爲兩類:
(1)字節流:用於處理字節數據。(InputStream,OutputStream)
(2)字符流:用於處理字符數據,Unicode字符數據。(Reader,Writer)
讀寫文件只要選一種實現這四個抽象類的實現類操作即可:
在Java中IO操作也是有相應步驟的,以文件操作爲例,主要的操作流程如下:
- 使用File類打開一個文件
- 通過字節流或字符流的子類,指定輸出的位置
- 進行讀/寫操作
- 關閉輸入/輸出
IO操作屬於資源操作,一定要記得關閉
字節流
InputStream : 是所有字節輸入流的父類,一般使用它的子類FileInputStream等,它能輸入字節流;
OutputStream : 是所有字節輸出流的父類,一般使用它的子類FileOutputStream等,它能輸出字節流;
FileInputStream:文件輸入流,用於從文件讀取數據,它的對象可以用關鍵字 new 來創建,它有多種構造方法可用來創建對象。
可以使用字符串類型的文件名來創建一個輸入流對象來讀取文件:
InputStream f = new FileInputStream("/data/data/包名/file/hello.text");
也可以使用一個文件對象來創建一個輸入流對象來讀取文件。我們首先得使用 File() 方法來創建一個文件對象:
File f = new File("/data/data/包名/file/hello.text");
InputStream out = new FileInputStream(f);
FileOutPutStream:文件輸出流,用於向文件寫入數據,如果該流在打開文件進行輸出前,目標文件不存在,該流不會創建該文件,並拋出FileNotFindException,有兩個構造方法可以用來創建 FileOutputStream 對象。
使用字符串類型的文件名來創建一個輸出流對象:
OutputStream f = new FileOutputStream("/data/data/包名/file/hello.text")
也可以使用一個文件對象來創建一個輸出流來寫文件。我們首先得使用File()方法來創建一個文件對象:
File f = new File("/data/data/包名/file/hello.text");
OutputStream f = new FileOutputStream(f);
輸入流讀數據
-
read()
從輸入流中讀取數據的下一個字節,返回0到255範圍內的int字節值。如果因爲已經到達流末尾而沒有可用的字節,則返回-1。在輸入數據可用、檢測到流末尾或者拋出異常前,此方法一直阻塞。因爲每次只能讀一個字節,所以速度很慢。 -
read(byte[] b)
從輸入流中讀取一定數量的字節,並將其存儲在緩衝區數組 b 中。以整數形式返回實際讀取的字節數。在輸入數據可用、檢測到文件末尾或者拋出異常前,此方法一直阻塞。如果 b 的長度爲 0,則不讀取任何字節並返回 0;否則,嘗試讀取至少一個字節。如果因爲流位於文件末尾而沒有可用的字節,則返回值 -1;否則,至少讀取一個字節並將其存儲在 b 中。將讀取的第一個字節存儲在元素 b[0] 中,下一個存儲在 b[1] 中,依次類推。讀取的字節數最多等於 b 的長度。設 k 爲實際讀取的字節數;這些字節將存儲在 b[0] 到 b[k-1] 的元素中,不影響 b[k] 到 b[b.length-1] 的元素。
輸出流寫數據
-
write(byte b)
與輸出流的read()對應,寫入單個字節 -
write(byte[] b,int off,int len)
將byte數組從off位到len位索引的數據寫入
//將輸入流每次讀1024個字節讀出,緩存到buf中,length是實際讀的字節數,然後將buf寫入到輸出流
int length = -1;
byte[] buf = new byte[1024];
while ((length = in.read(buf)) != -1) {
out.write(buf, 0, length);
}
字符流
Reader : 所有字符輸入流的父類,它以字符流的形式輸入
Writer : 所有字符輸出流的父類,它以字符流的形式輸出
FileReader:用來讀取字符文件的便捷類
InputStreamReader:InputStreamReader 是字節流通向字符流的橋樑:它使用指定的 charset 讀取字節並將其解碼爲字符。它使用的字符集可以由名稱指定或顯式給定,或者可以接受平臺默認的字符集。
BufferedReader:從字符輸入流中讀取文本,緩衝各個字符,從而實現字符、數組和行的高效讀取。
FileWriter:用來寫入字符文件的便捷類
OutputStreamWriter:OutputStreamWriter是字節流通向字符流的橋樑:它使用指定的 charset 讀取字節並將其解碼爲字符。它使用的字符集可以由名稱指定或顯式給定,或者可以接受平臺默認的字符集。
BufferedWriter:從字符輸出流中讀取文本,緩衝各個字符,從而實現字符、數組和行的高效寫入。
輸入流讀數據
讀取單個字符,公有方法
int read()
將字符讀入數組的某一部分,InputStreamReader和BufferedReader有
int read(char[] cbuf, int off, int len)
讀取一個文本行,只有BufferedWriter有
String readLine()
使用時可以先用FileWriter或InputStreamReader獲得字符流,再用BufferedReader封裝後每行讀取:
********************FileWriter******************************************
FileReader r = new FileReader(file);
BufferedReader br = new BufferedReader(r);
//由於每次只能讀一行,就讓其不斷地讀
StringBuffer msg = new StringBuffer();
String s;
while ((s = br.readLine()) != null) {
msg = msg.append(s+“\n”); //必須要加\n 否則全部數據變成一行
}
//別忘了釋放資源
r.close;
br.close;
********************InputStreamReader***********************************
InputStreamReader isr = new InputStreamReader(is, "UTF-8");//指定編碼格式
BufferedReader bfr = new BufferedReader(isr);
String in = "";
while ((in = bfr.readLine()) != null) {
Log.i(TAG, in);
}
//別忘了釋放資源
bfr.close();
isr.close();
輸出流寫數據
寫入單個字符
write(int c):
寫入字符串的某一部分
write(String str, int off, int len)
刷新此輸出流,並強制將所有已緩衝的輸出字節寫入該流中
flush()
關閉此流,但要先刷新它。在關閉該流之後,再調用 write() 或 flush() 將導致拋出 IOException。關閉以前關閉的流無效
close()
FileWriter和BufferedWriter配合寫入
BufferedWriter bw=null;
try {
bw=new BufferedWriter(new FileWriter("1.txt"));
bw.newLine();//自有換行符
bw.append('3');
bw.write("hello");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
bw.flush();
//使用BufferedWriter一定要在關閉前刷新
bw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}