1. 程式人生 > >Java:IO流之:探究位元組流和字元流

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陣列給程式,而位元組流每次只能傳一個位元組而已