Java:IO流之:探究位元組流和字元流
前言----
本來不想寫前言了,但是寫完,發現寫得太好了,遇到就好好看一看啊!!!!
注:歡迎轉載,轉載請註明來處
目錄
一. 簡單理解什麼是流?
我是把流理解成一個導管,這個導管連線了硬碟中的某個檔案和程式.
輸入流:輸入資料到程式(既從檔案中讀)
輸出流; 程式輸出資料到檔案(既寫到檔案)
二.位元組輸入流
正如我們所知, 計算機底層都是0和1, 有很多種編碼規則, 其作用就是將各自字元定義成特定的01串.,方便計算機識別.我們如果要從檔案中讀取字元,可以按位元組來進行讀取,這邊我們用FileInputStream來進行讀取,位元組流,按字面意思我們就知道要用byte或者byte陣列來進行讀取.
FileInputStream:
FileInputStream是繼承了抽象類InputStream。FileInputStream可以通過
1.int read() 從此輸入流中讀取一個位元組。
2int read(byte[] b ) 從此輸入流中將最多 b.length 個位元組的資料讀入一個 byte陣列中。
測試檔案:
:
demo(請細看程式碼和註釋)
package Test; import java.io.*; public class ByteStream { public static void main(String[] args) { // TODO Auto-generated method stub ByteStream myTest = new ByteStream(); myTest.testInputStream(); } public void creatFile(File f) { if(!f.exists()) {//先判斷檔案存不存在 //不存在的話,判斷判斷目錄存不存在 if(f.getParentFile().exists()!=true) { f.getParentFile().mkdirs();//不存在就建立 } //建立該檔案 try { f.createNewFile(); }catch(Exception e) { e.printStackTrace(); } } } public void testInputStream() { File f = new File("D:/data.txt"); creatFile(f);//若不存在可以自動建立 FileInputStream fis =null;// 先建立一個輸入流,初始為null try { //流建立失敗時會丟擲異常,應該try...catch或者throws fis = new FileInputStream(f); //建立一個大小等於檔案位元組大小的byte[]陣列 byte [] myByte = new byte[(int)f.length()]; //從檔案中一次讀取多個位元組 fis.read(myByte); //將byte位元組轉化為對應的字元 String str =new String(myByte); System.out.println(str); }catch(Exception e) { e.printStackTrace(); }finally { if(fis!=null) { try { fis.close();//記得關閉流,可能會關閉失敗,所以也要捕獲或者throws }catch(Exception e) { e.printStackTrace(); } } } } }
結果:
三.位元組輸出流
FileOutputStream 繼承了抽象類OutputStream, 意為檔案輸出流,是用於將資料寫入File,通過write方法將資料寫到檔案
1.void write(byte[] b)
將 b.length 個位元組從指定 byte 陣列寫入此檔案中。
2.void write(int b) 將指定位元組寫入此檔案。
- 寫入時不設定追寫 的話, 會先清空檔案再寫入
測試檔案:
demo(不要錯過註釋)
public void testOutputStream() {
File f = new File("D:data.txt");
creatFile(f);
try( FileOutputStream fos = new FileOutputStream(f) ){
//用輸出位元組流寫入檔案的時候,如果檔案不存在,但是父路徑存在,此時會自動建立對應的檔案
//如果對應的父目錄不存在的話就會丟擲異常
byte [] myByte = { 97,32,98,32,99};
fos.write(myByte);//一次寫到檔案的位元組長度為myByte的長度
/*
for(int i = 0 ;i <myByte.length; i++) {
fos.write(myByte[i] );//一個位元組一個位元組的寫入
fos.write("\r\n".getBytes());//換行寫入,在Windows寫換行符為"\r\n"
}
*/
}catch(Exception e) {
e.printStackTrace();
}
}
測試結果:原先的內容被清空了, 97,98,99對應的字元是abc, 32對應空格符
- 在原檔案的基礎上追加寫入( 使用FileOutputStream(f, true) )
測試文字:
demo:
//位元組輸出流,追加寫入
public void testOutputStream() {
File f = new File("D:/data.txt");
creatFile(f);
//追加寫入
try( FileOutputStream fos = new FileOutputStream(f,true) ){
//用輸出位元組流寫入檔案的時候,如果檔案不存在,但是父路徑存在,此時會自動建立對應的檔案
//如果對應的父目錄不存在的話就會丟擲異常
//引數為true代表追加寫入
byte [] myByte = { 97,32,98,32,99};
fos.write(myByte);//一次寫到檔案的位元組長度為myByte的長度
/*
for(int i = 0 ;i <myByte.length; i++) {
fos.write(myByte[i] );//一個位元組一個位元組的寫入
fos.write("\r\n".getBytes());//換行寫入,在Windows寫換行符為"\r\n"
}
*/
}catch(Exception e) {
e.printStackTrace();
}
}
測試結果:在原檔案的內容上成功追加寫入,而不會覆蓋掉
四.流的正確關閉方式
無論是輸入流還是輸出流,在使用完畢之後都應該進行關閉,否則會佔有資源, 如果為關閉的流很多的話,對程式的效能會有影響
1.在try{}內關閉,是不安全的關閉方式
2.在finally內關閉-----安全的寫法
3.用try-with-resource自動關閉
在JDK7以前,Java沒有自動關閉外部資源的語法特性,直到JDK7中新增了try-with-resource語法,才實現了這一功能.
五.字元輸入流
在不同的編碼規則下:一個字元可以佔多個位元組,那麼能不能一個字元一個字元地讀取到檔案呢?當然是可以的,我們用FileReader的read()進行讀取字元, 由於是字元流,自然是用char或char陣列來儲存讀取的字元
1.public int read(char[] cbuf) 一次性讀取cbuf.length個字元到cbuf中
2.public int read(char c) 一次讀取一個字元
測試檔案:
demo:
public void testFileReader() {
File f = new File("D:/data.txt");
try(FileReader fRe = new FileReader(f)){
//由於一個字元有多個字元,長度設為檔案的位元組長度,肯定夠用
char [] myChar =new char[(int)f.length()];
fRe.read(myChar);
for(char i : myChar) {
System.out.print(i);
}
}catch(Exception e) {
e.printStackTrace();
}
}
測試結果:
六.字元輸出流
用FileWriter把字元寫到檔案中, 用到它的write()方法:
- demo(不進行追寫,覆蓋掉原檔案)
測試之前:
public void testFileWriter() {
File f = new File("D:/data.txt");
isCreatFile(f);
try (FileWriter fWr = new FileWriter(f)){
char [] myChar= {'1','2','3','4','5'};
String myChar2 = "234324 34343";
fWr.write(myChar);
fWr.write("\r\n");//寫入換行符
fWr.write(myChar2);
}catch(Exception e) {
e.printStackTrace();
}
}
測試結果:
- demo( 用new FileWriter(f,true) 在原檔案的基礎上追寫,不覆蓋掉原檔案 )
測試之前:
public void testFileWriter() {
File f = new File("D:/data.txt");
isCreatFile(f);
try (FileWriter fWr = new FileWriter(f,true)){
char [] myChar= {'1','2','3','4','5'};
String myChar2 = "234324 34343";
fWr.write(myChar);
fWr.write("\r\n");
fWr.write(myChar2);
}catch(Exception e) {
e.printStackTrace();
}
}
測試結果:
七.位元組流和字元流的比較
問:字元流和位元組流的差別在哪裡,為什麼它能做到按字元讀取
答:
1.字元流的本質還是位元組流,檔案的底層儲存中都是01數字串,不存在字元的,我們開啟檔案看到的字元都是經過解碼後呈現出來的.
2.字元流的本質用到緩衝區,二者的工作示意圖如下所示:
大概就是說字元流可以在緩衝區的byte數組裡面形成一個byte陣列,然後直接傳byte陣列給程式,而位元組流每次只能傳一個位元組而已