2021.01.31 第一階段 17
技術標籤:第一階段
*1、遞迴和File的練習
2、IO概述
3、位元組流
4、字元流
*
一、遞迴和File的練習
(一)練習
鍵盤錄入一個資料夾路徑,使用遞迴列印這個資料夾下的所有檔案的絕對路徑
分析:
一個方法:使用遞迴必須要有方法自己呼叫自己
兩個分支:
需要遞迴:遇到資料夾,就重複上一次開啟資料夾的動作,獲取裡面的內容
不用遞迴:遇到檔案,就不需要遞迴,而是直接獲取列印檔案的絕對路徑即可
import java.io.File;
import com.offcn.homework.Homework04;
/**
* 鍵盤錄入一個資料夾路徑,使用遞迴列印這個資料夾下的所有檔案的絕對路徑
*
*/
public class Demo01_Exercise {
public static void main(String[] args) {
File dir = Homework04.getDir();
printFilePath(dir);
}
public static void printFilePath(File dir) {
//1.開啟資料夾,將資料夾下所有的內容,全都轉為File物件,便於操作
File[] files = dir.listFiles();
//2.遍歷獲取每一個File物件,進行具體操作
for (File file : files) {
//3.如果是檔案,就列印絕對路徑,如果是資料夾,就進入到資料夾中,操作內容
if(file.isFile()) {
System.out.println(file.getAbsolutePath());
} else {
printFilePath(file);
}
}
}
}
(二)總結
1、所有能夠使用遞迴完成的操作都有其他的解法,但是其他的解法相較於遞迴而言,比較難並且不方便操作
2、遞迴的優點:程式碼比較簡單,按照遞迴的方式思考,比較容易
3、遞迴的缺點:遞迴是將所有的方法一口氣全部載入進棧,之後再一個個執行彈棧,如果記憶體較小,或
4、StackOverflow是一個國外網站的名稱,類似於是一個專業版的知乎
二、IO概述
(一)基本概念
1、IO:是input和output的縮寫,input輸入,output輸出
2、【Java中,所有的IO都是站在記憶體的角度說明】,一切其它裝置進記憶體的操作,都是輸入;一切記憶體到其他裝置的操作,都是輸出。
3、基本概念:
(1)硬碟:用於儲存資料
(2)記憶體:用於資料指令執行
(二)IO分類
1、分類的方式有兩種:按照流向分,按照功能分
2、按照流向分:
(1)輸入流:從其它裝置到記憶體
(2)輸出流:從記憶體到其它裝置
3、按照功能分:
(1)位元組流:可以直接操作檔案的位元組資訊
(2)字元流:一般用於操作文字文件的字元內容
4、體系結構:
(三)IO程式書寫的注意事項
1、【所有IO流物件,在使用完畢之後,都要記得關閉資源】
2、Java所有IO相關的內容,都在IO包下,記得導包,並且不要導錯
3、大部分IO流存在一些編譯時異常,我們需要合理處理異常
三、位元組流
(一)概述
1、可以直接操作位元組資訊的流物件,計算機中所有內容都用位元組資訊進行儲存,所以這種流可以操作所有內容
2、根據流向,可以分為位元組輸入流,位元組輸出流
3、頂層抽象父類是:InputStream和OutputSream
4、根據互動裝置的不同,有不同的實現子類,例如和磁碟互動,用於操作磁碟檔案的實現類:
FileInputStream、FileOutputStream
(二)InputStream
1、位元組輸入流的頂層抽象父類
2、常用方法:
(1)read() 從輸入流中讀取資料的下一個位元組
(2)read(byte[] b) 從輸入流中讀取一定數量的位元組,並將其儲存在緩衝區陣列 b 中
(3)available() 返回要讀取的檔案中總的位元組個數
(4)close() 關閉資源
3、因為InputStream是一個抽象類,所以無法例項化,如果要使用,需要根據具體的互動裝置,建立實現子類的物件
(三)FileInputStream
1、是InputStream的一個具體的實現子類,用於和磁碟上的檔案進行互動
2、構造方法:
(1)FileInputStream(String name) 使用字串表示一個檔案的路徑,建立一個位元組流物件,將
來用於讀取檔案位元組資訊(將檔案的位元組資訊輸入到記憶體)
(2)FileInputStream(File file) 使用File物件表示一個檔案的路徑,建立一個位元組流物件,將來用
於讀取檔案位元組資訊(將檔案的位元組資訊輸入到記憶體)
3、常用方法:
(1)read() 從輸入流中讀取資料的下一個位元組資訊,返回它的int表示形式,當我們已經讀取到了文
件末尾,則會返回-1。在實際操作中,即便檔案中的內容有負數存在,讀取到以後,也會是一個整數,
不可能在記憶體中出現負數,如果這的返回了負數,那一定是流到達末尾,自動返回的
(2)read(byte[] b) 從輸入流中讀取一定數量的位元組,並將其儲存在緩衝區陣列 b 中
(四)OutputStream
1、位元組輸出流的頂層抽象父類
2、常用方法:
(1)write(int b) 向輸出流物件所關聯的位置輸出一個位元組資訊
(2)write(byte[] b) 向輸出流物件所關聯的位置輸出一個位元組資訊的陣列
(3)write(byte[] b, int off, int len) 向輸出流物件所關聯的位置輸出一個位元組資訊陣列的一部分
(4)flush() 重新整理緩衝區
3、這個型別是抽象的,根據互動裝置的不同,由不同的實現子類來建立物件
(五)FileOutputStream
1、可以將記憶體中的位元組資訊,輸出到指定的檔案中
2、構造方法:
(1)FileOutputStream(String name) 建立輸出流物件,可以將位元組資訊輸出到String字串表示的具體檔案中
(2)FileOutputStream(File file) 建立輸出流物件,可以將位元組資訊輸出到File物件表示的具體檔案中
3、注意事項:
(1)使用位元組輸出流,將記憶體中Java程式碼提供的位元組資訊輸出到磁碟上的檔案裡,不存在編碼操作,也不存在解碼操作,僅僅是將位元組資訊,從記憶體中輸出到了磁碟中
(2)但是當我們使用某些格式開啟檔案的時候,例如txt,就會按照txt的規則,將檔案中的位元組資訊解碼成人類語言
(六)檔案拷貝
1、含義:將一個檔案中的位元組資訊,拷貝到另一個檔案中
2、本質:從一個檔案中,使用輸入流讀取一個位元組資訊,將這個位元組資訊,通過輸出流,輸出到另外一
個檔案中
3、圖示:
(七)檔案拷貝效率提升
1、使用逐個位元組拷貝的方式,效率非常低:
(1)磁碟執行速度慢,頻繁訪問磁碟效率會變低
(2)每次拷貝一個位元組資訊,就要訪問2次磁碟,次數過多本身就會降低效率
2、提升思路:一次多讀取一些位元組資訊,一次多輸出一些位元組資訊,減少訪問磁碟次數,來提高效率
3、方式一:使用read(byte[] arr)方法,一次讀取一個數組長度的位元組資訊,結合write(byte[] arr)方
法,將一整個陣列直接寫出,陣列的大小就是檔案中位元組個數
4、方拾二:由於方式一,陣列等於檔案位元組數,當檔案過大,比計算機記憶體還要大,就無法實現用大數
組拷貝,可以將陣列設定小一點,也可以提升效率。例如:陣列長度設定為2
5、方式三:由於方拾二中,陣列的長度問題,當檔案位元組個數為奇數的時候,而陣列如果定義為偶數,
最後一次的拷貝,很有可能陣列裝不滿,會帶有最後一次和倒數第二次的拷貝結果,輸出的時候,又是
整個陣列進行輸出的,所以結果會有問題。輸出是產生問題的關鍵!輸出的時候,本次讀取到了多少內
容,就輸出多少內容,沒有讀取到的就不輸出,要使用write(byte[] , int index, int len)進行輸出,可以
解決問題
6、注意事項:我們以後拷貝,都採用小陣列的方案
(1)陣列的大小可以自己設定,陣列越大,效率越高,因為訪問磁碟的次數越少
(2)一般情況下,陣列的容積都採用1024的整數倍,官方經常使用1024*8作為緩衝區的大小
(八)read()方法和read(byte[] arr)方法的總結
1、int read() 一次讀取一個位元組資訊,返回的是讀取到的具體位元組資訊的int表示形式,當到達檔案末尾,返回-1
2、int read(byte[] arr) 一次讀取一個數組長度的位元組資訊,返回的是當前一次讀取到的位元組個數,當到達檔案末尾,返回-1
三、高效緩衝位元組流
1、高效緩衝位元組輸入流:BufferedInputStream,高效緩衝位元組輸出流:BufferedOutputStream
2、高效緩衝流都是包裝類:本身不具有讀寫功能,只是在其他具有讀寫功能的流上進行功能的加強,例
如:FileInputStream和FileOutputStream本身效率不高,但是通過高效流加強,效率就會得到提升
3、構造方法:
(1)高效緩衝位元組輸入流:BufferedInputStream(InputStream in) 將引數指定的、具有讀寫功能
的流傳入,形成一個具有高效讀寫功能的流物件
(2)高效緩衝位元組輸出流:BufferedOutputStream(OutputStream out) 將引數指定的、具有讀
寫功能的流傳入,形成一個具有高效讀寫功能的流物件
4、使用:還是和加強之前的使用沒有差別
5、高效的原因:
(1)BufferedInputStream高效原因:這個型別中封裝了一個長度為8192的byte[],用於儲存位元組信
息,當呼叫read()方法的時,該物件一次性從磁盤獲取8192個位元組資訊到陣列中,只將第一個位元組資訊
返回給呼叫者,後來每一次呼叫read()方法的時候,都不會再去訪問磁碟,而是從記憶體裡的陣列中拿取
一個位元組資訊返回給呼叫者,由於讀取的是記憶體中的陣列,而不是磁碟上的檔案,減少了磁碟的訪問次
數,所以效率提升明顯。當8192個位元組資訊都讀取完畢了,下一次,才會再去訪問一次磁碟,再獲取
8192個位元組資訊
(2)BufferedOutputStream高效原因:這個型別中封裝了一個長度為8192的byte[],用於儲存位元組
資訊,當呼叫write(int b)一次寫出一個位元組資訊,並不會將位元組資訊直接輸出到磁碟上,而是將自己信
息儲存到陣列中,當陣列完全裝滿,才會向磁碟輸出一次,一次輸出8192個位元組資訊。這種方式也是減
少了訪問磁碟的次數,來提高效率。