###20.01_IO流(IO流概述及其分類)
- 1.概念
- IO流用來處理裝置之間的資料傳輸
- Java對資料的操作是通過流的方式
- Java用於操作流的類都在IO包中
- 流按流向分為兩種:輸入流,輸出流。
- 流按操作型別分為兩種:
- 位元組流 : 位元組流可以操作任何資料,因為在計算機中任何資料都是以位元組的形式儲存的
- 字元流 : 字元流只能操作純字元資料,比較方便。
- 2.IO流常用父類
- 位元組流的抽象父類:
- InputStream
- OutputStream
- 字元流的抽象父類:
- Reader
- Writer
- 位元組流的抽象父類:
- 3.IO程式書寫
- 使用前,匯入IO包中的類
- 使用時,進行IO異常處理
- 使用後,釋放資源
###20.02_IO流(FileInputStream)
- read()一次讀取一個位元組
-
FileInputStream fis = new FileInputStream("aaa.txt"); //建立一個檔案輸入流物件,並關聯aaa.txt int b; //定義變數,記錄每次讀到的位元組 while((b = fis.read()) != -1) { //將每次讀到的位元組賦值給b並判斷是否是-1 System.out.println(b); //列印每一個位元組 } fis.close(); //關閉流釋放資源 複製程式碼
###20.03_IO流(FileInputStream返回值為什麼是int)
- read()方法讀取的是一個位元組,為什麼返回是int,而不是byte
-
因為位元組輸入流可以操作任意型別的檔案,比如圖片音訊等,這些檔案底層都是以二進位制形式的儲存的,如果每次讀取都返回byte,有可能在讀到中間的時候遇到111111111 那麼這11111111是byte型別的-1,我們的程式是遇到-1就會停止不讀了,後面的資料就讀不到了,所以在讀取的時候用int型別接收,如果11111111會在其前面補上 24個0湊足4個位元組,那麼byte型別的-1就變成int型別的255了這樣可以保證整個資料讀完,而結束標記的-1就是int型別 複製程式碼
###20.04_IO流(FileOutputStream)
- write()一次寫出一個位元組
-
FileOutputStream fos = new FileOutputStream("bbb.txt"); //如果沒有bbb.txt,會建立出一個 //fos.write(97); //雖然寫出的是一個int數,但是在寫出的時候會將前面的24個0去掉,所以寫出的一個byte fos.write(98); fos.write(99); fos.close(); 複製程式碼
###20.05_IO流(FileOutputStream追加)
- A:案例演示
- FileOutputStream的構造方法寫出資料如何實現資料的追加寫入
-
FileOutputStream fos = new FileOutputStream("bbb.txt",true); //如果沒有bbb.txt,會建立出一個 //fos.write(97); //雖然寫出的是一個int數,但是在寫出的時候會將前面的24個0去掉,所以寫出的一個byte fos.write(98); fos.write(99); fos.close(); 複製程式碼
###20.06_IO流(拷貝圖片)
-
FileInputStream讀取
-
FileOutputStream寫出
FileInputStream fis = new FileInputStream("致青春.mp3"); //建立輸入流物件,關聯a.jpg FileOutputStream fos = new FileOutputStream("copy.mp3");//建立輸出流物件,關聯b.jpg int b; while((b = fis.read()) != -1) { fos.write(b); } fis.close(); fos.close(); 複製程式碼
###20.07_IO流(拷貝音訊檔案畫原理圖)
- A:案例演示
- 位元組流一次讀寫一個位元組複製音訊
- 弊端:效率太低
###20.08_IO流(位元組陣列拷貝之available()方法)
-
A:案例演示
- int read(byte[] b):一次讀取一個位元組陣列
- write(byte[] b):一次寫出一個位元組陣列
- available()獲取讀的檔案所有的位元組個數
-
弊端:有可能會記憶體溢位
FileInputStream fis = new FileInputStream("致青春.mp3"); FileOutputStream fos = new FileOutputStream("copy.mp3"); byte[] arr = new byte[fis.available()]; //根據檔案大小做一個位元組陣列 fis.read(arr); //將檔案上的所有位元組讀取到陣列中 fos.write(arr); //將陣列中的所有位元組一次寫到了檔案上 fis.close(); fos.close(); 複製程式碼
###20.09_IO流(定義小陣列)
- write(byte[] b)
- write(byte[] b, int off, int len)寫出有效的位元組個數
###20.10_IO流(定義小陣列的標準格式)
-
A:案例演示
-
位元組流一次讀寫一個位元組陣列複製圖片和視訊 FileInputStream fis = new FileInputStream("致青春.mp3"); FileOutputStream fos = new FileOutputStream("copy.mp3"); int len; byte[] arr = new byte[1024 * 8]; //自定義位元組陣列
while((len = fis.read(arr)) != -1) { //fos.write(arr); fos.write(arr, 0, len); //寫出位元組陣列寫出有效個位元組個數 }
fis.close(); fos.close(); ###20.11_IO流(BufferedInputStream和BufferOutputStream拷貝)
-
-
A:緩衝思想
- 位元組流一次讀寫一個陣列的速度明顯比一次讀寫一個位元組的速度快很多,
- 這是加入了陣列這樣的緩衝區效果,java本身在設計的時候,
- 也考慮到了這樣的設計思想(裝飾設計模式後面講解),所以提供了位元組緩衝區流
-
B.BufferedInputStream
- BufferedInputStream內建了一個緩衝區(陣列)
- 從BufferedInputStream中讀取一個位元組時
- BufferedInputStream會一次性從檔案中讀取8192個, 存在緩衝區中, 返回給程式一個
- 程式再次讀取時, 就不用找檔案了, 直接從緩衝區中獲取
- 直到緩衝區中所有的都被使用過, 才重新從檔案中讀取8192個
-
C.BufferedOutputStream
- BufferedOutputStream也內建了一個緩衝區(陣列)
- 程式向流中寫出位元組時, 不會直接寫到檔案, 先寫到緩衝區中
- 直到緩衝區寫滿, BufferedOutputStream才會把緩衝區中的資料一次性寫到檔案裡
-
D.拷貝的程式碼
FileInputStream fis = new FileInputStream("致青春.mp3"); //建立檔案輸入流物件,關聯致青春.mp3 BufferedInputStream bis = new BufferedInputStream(fis); //建立緩衝區對fis裝飾 FileOutputStream fos = new FileOutputStream("copy.mp3"); //建立輸出流物件,關聯copy.mp3 BufferedOutputStream bos = new BufferedOutputStream(fos); //建立緩衝區對fos裝飾 int b; while((b = bis.read()) != -1) { bos.write(b); } bis.close(); //只關裝飾後的物件即可 bos.close(); 複製程式碼
###20.12_IO流(小陣列的讀寫和帶Buffered的讀取哪個更快)
- 定義小陣列如果是8192個位元組大小和Buffered比較的話
- 定義小陣列會略勝一籌,因為讀和寫操作的是同一個陣列
- 而Buffered操作的是兩個陣列
###20.13_IO流(flush和close方法的區別)
- flush()方法
- 用來重新整理緩衝區的,重新整理後可以再次寫出
- close()方法
- 用來關閉流釋放資源的的,如果是帶緩衝區的流物件的close()方法,不但會關閉流,還會再關閉流之前重新整理緩衝區,關閉後不能再寫出 ###20.14_IO流(位元組流讀寫中文)
- 位元組流讀取中文的問題
- 位元組流在讀中文的時候有可能會讀到半個中文,造成亂碼
- 位元組流寫出中文的問題
- 位元組流直接操作的位元組,所以寫出中文必須將字串轉換成位元組陣列
- 寫出回車換行 write("\r\n".getBytes());
###20.15_IO流(流的標準處理異常程式碼1.6版本及其以前)
-
try finally巢狀
FileInputStream fis = null; FileOutputStream fos = null; try { fis = new FileInputStream("aaa.txt"); fos = new FileOutputStream("bbb.txt"); int b; while((b = fis.read()) != -1) { fos.write(b); } } finally { try { if(fis != null) fis.close(); }finally { if(fos != null) fos.close(); } } 複製程式碼
###20.16_IO流(流的標準處理異常程式碼1.7版本)
-
try close
try( FileInputStream fis = new FileInputStream("aaa.txt"); FileOutputStream fos = new FileOutputStream("bbb.txt"); MyClose mc = new MyClose(); ){ int b; while((b = fis.read()) != -1) { fos.write(b); } } 複製程式碼
-
原理
- 在try()中建立的流物件必須實現了AutoCloseable這個介面,如果實現了,在try後面的{}(讀寫程式碼)執行後就會自動呼叫,流物件的close方法將流關掉
###20.17_IO流(圖片加密)
-
給圖片加密
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.jpg")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.jpg")); int b; while((b = bis.read()) != -1) { bos.write(b ^ 123); } bis.close(); bos.close(); 複製程式碼
###20.18_IO流(拷貝檔案)
-
在控制檯錄入檔案的路徑,將檔案拷貝到當前專案下
Scanner sc = new Scanner(System.in); System.out.println("請輸入一個檔案路徑"); String line = sc.nextLine(); //將鍵盤錄入的檔案路徑儲存在line中 File file = new File(line); //封裝成File物件 FileInputStream fis = new FileInputStream(file); FileOutputStream fos = new FileOutputStream(file.getName()); int len; byte[] arr = new byte[8192]; //定義緩衝區 while((len = fis.read(arr)) != -1) { fos.write(arr,0,len); } fis.close(); fos.close(); 複製程式碼
###20.19_IO流(錄入資料拷貝到檔案)
-
將鍵盤錄入的資料拷貝到當前專案下的text.txt檔案中,鍵盤錄入資料當遇到quit時就退出
Scanner sc = new Scanner(System.in); FileOutputStream fos = new FileOutputStream("text.txt"); System.out.println("請輸入:"); while(true) { String line = sc.nextLine(); if("quit".equals(line)) break; fos.write(line.getBytes()); fos.write("\r\n".getBytes()); } fos.close(); 複製程式碼