Java 的異常以及File類

瑪拉_以琳發表於2023-04-27

1. 異常

1.1 異常概念

異常,就是不正常的意思。在生活中:醫生說,你的身體某個部位有異常,該部位和正常相比有點不同,該部位的功能將受影響.在程式中的意思就是:

  • 異常 :指的是程式在執行過程中,出現的非正常的情況,最終會導致JVM的非正常停止。

在Java等物件導向的程式語言中,異常本身是一個類,產生異常就是建立異常物件並丟擲了一個異常物件。Java處理異常的方式是中斷處理。

異常指的並不是語法錯誤,語法錯了,編譯不透過,不會產生位元組碼檔案,根本不能執行.

1.2 異常體系

異常機制其實是幫助我們找到程式中的問題,異常的根類是java.lang.Throwable,其下有兩個子類:java.lang.Errorjava.lang.Exception,平常所說的異常指java.lang.Exception
異常體系.png

Throwable體系:

  • Error:嚴重錯誤Error,無法透過處理的錯誤,只能事先避免,好比絕症。
  • Exception:表示異常,異常產生後程式設計師可以透過程式碼的方式糾正,使程式繼續執行,是必須要處理的。好比感冒、闌尾炎。

Throwable中的常用方法:

  • public void printStackTrace():列印異常的詳細資訊。

    包含了異常的型別,異常的原因,還包括異常出現的位置,在開發和除錯階段,都得使用printStackTrace。

  • public String getMessage():獲取發生異常的原因。

    提示給使用者的時候,就提示錯誤原因。

  • public String toString():獲取異常的型別和異常描述資訊(不用)。

出現異常,不要緊張,把異常的簡單類名,複製到API中去查。
![上傳中...]()

1.3 異常分類

我們平常說的異常就是指Exception,因為這類異常一旦出現,我們就要對程式碼進行更正,修復程式。

異常(Exception)的分類:根據在編譯時期還是執行時期去檢查異常?

  • 編譯時期異常:checked異常。在編譯時期,就會檢查,如果沒有處理異常,則編譯失敗。(如日期格式化異常)
  • 執行時期異常:runtime異常。在執行時期,檢查異常.在編譯時期,執行異常不會編譯器檢測(不報錯)。(如數學異常)

異常的分類.png

1.4 異常的產生過程解析

先執行下面的程式,程式會產生一個陣列索引越界異常ArrayIndexOfBoundsException。我們透過圖解來解析下異常產生的過程。

工具類

public class ArrayTools {
    // 對給定的陣列透過給定的角標獲取元素。
    public static int getElement(int[] arr, int index) {
        int element = arr[index];
        return element;
    }
}

測試類

public class ExceptionDemo {
    public static void main(String[] args) {
        int[] arr = { 34, 12, 67 };
        intnum = ArrayTools.getElement(arr, 4)
        System.out.println("num=" + num);
        System.out.println("over");
    }
}

上述程式執行過程圖解:

異常產生過程.png

1.5 丟擲異常throw

在編寫程式時,我們必須要考慮程式出現問題的情況。比如,在定義方法時,方法需要接受引數。那麼,當呼叫方法使用接受到的引數時,首先需要先對引數資料進行合法的判斷,資料若不合法,就應該告訴呼叫者,傳遞合法的資料進來。這時需要使用丟擲異常的方式來告訴呼叫者。

在java中,提供了一個throw關鍵字,它用來丟擲一個指定的異常物件。那麼,丟擲一個異常具體如何操作呢?

  1. 建立一個異常物件。封裝一些提示資訊(資訊可以自己編寫)。
  2. 需要將這個異常物件告知給呼叫者。怎麼告知呢?怎麼將這個異常物件傳遞到呼叫者處呢?透過關鍵字throw就可以完成。throw 異常物件。

    throw用在方法內,用來丟擲一個異常物件,將這個異常物件傳遞到呼叫者處,並結束當前方法的執行。

使用格式:

throw new 異常類名(引數);

例如:

throw new NullPointerException("要訪問的arr陣列不存在");

throw new ArrayIndexOutOfBoundsException("該索引在陣列中不存在,已超出範圍");

學習完丟擲異常的格式後,我們透過下面程式演示下throw的使用。

public class ThrowDemo {
    public static void main(String[] args) {
        //建立一個陣列 
        int[] arr = {2,4,52,2};
        //根據索引找對應的元素 
        int index = 4;
        int element = getElement(arr, index);

        System.out.println(element);
        System.out.println("over");
    }
    /*
     * 根據 索引找到陣列中對應的元素
     */
    public static int getElement(int[] arr,int index){ 
           //判斷  索引是否越界
        if(index<0 || index>arr.length-1){
             /*
             判斷條件如果滿足,當執行完throw丟擲異常物件後,方法已經無法繼續運算。
             這時就會結束當前方法的執行,並將異常告知給呼叫者。這時就需要透過異常來解決。 
              */
             throw new ArrayIndexOutOfBoundsException("哥們,角標越界了```");
        }
        int element = arr[index];
        return element;
    }
}

注意:如果產生了問題,我們就會throw將問題描述類即異常進行丟擲,也就是將問題返回給該方法的呼叫者。

那麼對於呼叫者來說,該怎麼處理呢?一種是進行捕獲處理,另一種就是繼續講問題宣告出去,使用throws宣告處理。

1.6 宣告異常throws

宣告異常:將問題標識出來,報告給呼叫者。如果方法內透過throw丟擲了編譯時異常,而沒有捕獲處理(稍後講解該方式),那麼必須透過throws進行宣告,讓呼叫者去處理。

關鍵字throws運用於方法宣告之上,用於表示當前方法不處理異常,而是提醒該方法的呼叫者來處理異常(丟擲異常).

宣告異常格式:

修飾符 返回值型別 方法名(引數) throws 異常類名1,異常類名2…{   }    

宣告異常的程式碼演示:

public class ThrowsDemo {
    public static void main(String[] args) throws FileNotFoundException {
        read("a.txt");
    }

    // 如果定義功能時有問題發生需要報告給呼叫者。可以透過在方法上使用throws關鍵字進行宣告
    public static void read(String path) throws FileNotFoundException {
        if (!path.equals("a.txt")) {//如果不是 a.txt這個檔案 
            // 我假設  如果不是 a.txt 認為 該檔案不存在 是一個錯誤 也就是異常  throw
            throw new FileNotFoundException("檔案不存在");
        }
    }
}

throws用於進行異常類的宣告,若該方法可能有多種異常情況產生,那麼在throws後面可以寫多個異常類,用逗號隔開。

public class ThrowsDemo2 {
    public static void main(String[] args) throws IOException {
        read("a.txt");
    }

    public static void read(String path)throws FileNotFoundException, IOException {
        if (!path.equals("a.txt")) {//如果不是 a.txt這個檔案 
            // 我假設  如果不是 a.txt 認為 該檔案不存在 是一個錯誤 也就是異常  throw
            throw new FileNotFoundException("檔案不存在");
        }
        if (!path.equals("b.txt")) {
            throw new IOException();
        }
    }
}

1.7 捕獲異常try…catch

如果異常出現的話,會立刻終止程式,所以我們得處理異常:

  1. 該方法不處理,而是宣告丟擲,由該方法的呼叫者來處理(throws)。
  2. 在方法中使用try-catch的語句塊來處理異常。

try-catch的方式就是捕獲異常。

  • 捕獲異常:Java中對異常有針對性的語句進行捕獲,可以對出現的異常進行指定方式的處理。

捕獲異常語法如下:

try{
     編寫可能會出現異常的程式碼
}catch(異常型別  e){
     處理異常的程式碼
     //記錄日誌/列印異常資訊/繼續丟擲異常
}

try:該程式碼塊中編寫可能產生異常的程式碼。

catch:用來進行某種異常的捕獲,實現對捕獲到的異常進行處理。

注意:try和catch都不能單獨使用,必須連用。

演示如下:

public class TryCatchDemo {
    public static void main(String[] args) {
        try {// 當產生異常時,必須有處理方式。要麼捕獲,要麼宣告。
            read("b.txt");
        } catch (FileNotFoundException e) {// 括號中需要定義什麼呢?
              //try中丟擲的是什麼異常,在括號中就定義什麼異常型別
            System.out.println(e);
        }
        System.out.println("over");
    }
    /*
     *
     * 我們 當前的這個方法中 有異常  有編譯期異常
     */
    public static void read(String path) throws FileNotFoundException {
        if (!path.equals("a.txt")) {//如果不是 a.txt這個檔案 
            // 我假設  如果不是 a.txt 認為 該檔案不存在 是一個錯誤 也就是異常  throw
            throw new FileNotFoundException("檔案不存在");
        }
    }
}

如何獲取異常資訊:

Throwable類中定義了一些檢視方法:

  • public String getMessage():獲取異常的描述資訊,原因(提示給使用者的時候,就提示錯誤原因。
  • public String toString():獲取異常的型別和異常描述資訊(不用)。
  • public void printStackTrace():列印異常的跟蹤棧資訊並輸出到控制檯。

包含了異常的型別,異常的原因,還包括異常出現的位置,在開發和除錯階段,都得使用printStackTrace。

在開發中呢也可以在catch將編譯期異常轉換成執行期異常處理。

多個異常使用捕獲又該如何處理呢?

  1. 多個異常分別處理。
  2. 多個異常一次捕獲,多次處理。
  3. 多個異常一次捕獲一次處理。

一般我們是使用一次捕獲多次處理方式,格式如下:

try{
     編寫可能會出現異常的程式碼
}catch(異常型別A  e){  當try中出現A型別異常,就用該catch來捕獲.
     處理異常的程式碼
     //記錄日誌/列印異常資訊/繼續丟擲異常
}catch(異常型別B  e){  當try中出現B型別異常,就用該catch來捕獲.
     處理異常的程式碼
     //記錄日誌/列印異常資訊/繼續丟擲異常
}
注意:這種異常處理方式,要求多個catch中的異常不能相同,並且若catch中的多個異常之間有子父類異常的關係,那麼子類異常要求在上面的catch處理,父類異常在下面的catch處理。

1.8 finally 程式碼塊

finally:有一些特定的程式碼無論異常是否發生,都需要執行。另外,因為異常會引發程式跳轉,導致有些語句執行不到。而finally就是解決這個問題的,在finally程式碼塊中存放的程式碼都是一定會被執行的。

什麼時候的程式碼必須最終執行?

當我們在try語句塊中開啟了一些物理資源(磁碟檔案/網路連線/資料庫連線等),我們都得在使用完之後,最終關閉開啟的資源。

finally的語法:

try...catch....finally:自身需要處理異常,最終還得關閉資源。

注意:finally不能單獨使用。

比如在我們之後學習的IO流中,當開啟了一個關聯檔案的資源,最後程式不管結果如何,都需要把這個資源關閉掉。

finally程式碼參考如下:

public class TryCatchDemo4 {
    public static void main(String[] args) {
        try {
            read("a.txt");
        } catch (FileNotFoundException e) {
            //抓取到的是編譯期異常  丟擲去的是執行期 
            throw new RuntimeException(e);
        } finally {
            System.out.println("不管程式怎樣,這裡都將會被執行。");
        }
        System.out.println("over");
    }
    /*
     *
     * 我們 當前的這個方法中 有異常  有編譯期異常
     */
    public static void read(String path) throws FileNotFoundException {
        if (!path.equals("a.txt")) {//如果不是 a.txt這個檔案 
            // 我假設  如果不是 a.txt 認為 該檔案不存在 是一個錯誤 也就是異常  throw
            throw new FileNotFoundException("檔案不存在");
        }
    }
}
當只有在try或者catch中呼叫退出JVM的相關方法,此時finally才不會執行,否則finally永遠會執行。

1.9 異常注意事項

  • 執行時異常被丟擲可以不處理。即不捕獲也不宣告丟擲。
  • 如果父類丟擲了多個異常,子類覆蓋父類方法時,只能丟擲相同的異常或者是他的子集。
  • 父類方法沒有丟擲異常,子類覆蓋父類該方法時也不可丟擲異常。此時子類產生該異常,只能捕獲處理,不能宣告丟擲
  • 當多異常處理時,捕獲處理,前邊的類不能是後邊類的父類
  • 在try/catch後可以追加finally程式碼塊,其中的程式碼一定會被執行,通常用於資源回收。

1.10 概述

為什麼需要自定義異常類:

我們說了Java中不同的異常類,分別表示著某一種具體的異常情況,那麼在開發中總是有些異常情況是SUN沒有定義好的,此時我們根據自己業務的異常情況來定義異常類。,例如年齡負數問題,考試成績負數問題。

在上述程式碼中,發現這些異常都是JDK內部定義好的,但是實際開發中也會出現很多異常,這些異常很可能在JDK中沒有定義過,例如年齡負數問題,考試成績負數問題.那麼能不能自己定義異常呢?

什麼是自定義異常類:

在開發中根據自己業務的異常情況來定義異常類.

自定義一個業務邏輯異常: LoginException。一個登陸異常類。

異常類如何定義:

  1. 自定義一個編譯期異常: 自定義類 並繼承於java.lang.Exception
  2. 自定義一個執行時期的異常類:自定義類 並繼承於java.lang.RuntimeException

1.11 自定義異常的練習

要求:我們模擬登陸操作,如果使用者名稱已存在,則丟擲異常並提示:親,該使用者名稱已經被註冊。

首先定義一個登陸異常類LoginException:

// 業務邏輯異常
public class LoginException extends Exception {
    /**
     * 空參構造
     */
    public LoginException() {
    }

    /**
     *
     * @param message 表示異常提示
     */
    public LoginException(String message) {
        super(message);
    }
}

模擬登陸操作,使用陣列模擬資料庫中儲存的資料,並提供當前註冊賬號是否存在方法用於判斷。

public class Demo {
    // 模擬資料庫中已存在賬號
    private static String[] names = {"bill","hill","jill"};
   
    public static void main(String[] args) {     
        //呼叫方法
        try{
            // 可能出現異常的程式碼
            checkUsername("nill");
            System.out.println("註冊成功");//如果沒有異常就是註冊成功
        } catch(LoginException e) {
            //處理異常
            e.printStackTrace();
        }
    }

    //判斷當前註冊賬號是否存在
    //因為是編譯期異常,又想呼叫者去處理 所以宣告該異常
    public static boolean checkUsername(String uname) throws LoginException {
        for (String name : names) {
            if(name.equals(uname)){//如果名字在這裡面 就丟擲登陸異常
                throw new LoginException("親"+name+"已經被註冊了!");
            }
        }
        return true;
    }
}

2. File類

2.1 概述

java.io.File 類是檔案和目錄路徑名的抽象表示,主要用於檔案和目錄的建立、查詢和刪除等操作。

2.2 構造方法

  • public File(String pathname) :透過將給定的路徑名字串轉換為抽象路徑名來建立新的 File例項。
  • public File(String parent, String child) :從父路徑名字串和子路徑名字串建立新的 File例項。
  • public File(File parent, String child) :從父抽象路徑名和子路徑名字串建立新的 File例項。
  • 構造舉例,程式碼如下:
// 檔案路徑名
String pathname = "D:\\aaa.txt";
File file1 = new File(pathname); 

// 檔案路徑名
String pathname2 = "D:\\aaa\\bbb.txt";
File file2 = new File(pathname2); 

// 透過父路徑和子路徑字串
 String parent = "d:\\aaa";
 String child = "bbb.txt";
 File file3 = new File(parent, child);

// 透過父級File物件和子路徑字串
File parentDir = new File("d:\\aaa");
String child = "bbb.txt";
File file4 = new File(parentDir, child);

小貼士:

  1. 一個File物件代表硬碟中實際存在的一個檔案或者目錄。
  2. 無論該路徑下是否存在檔案或者目錄,都不影響File物件的建立。

2.3 常用方法

獲取功能的方法

  • public String getAbsolutePath() :返回此File的絕對路徑名字串。
  • public String getPath() :將此File轉換為路徑名字串。
  • public String getName() :返回由此File表示的檔案或目錄的名稱。
  • public long length() :返回由此File表示的檔案的長度。

    方法演示,程式碼如下:

    public class FileGet {
        public static void main(String[] args) {
            File f = new File("d:/aaa/bbb.java");     
            System.out.println("檔案絕對路徑:"+f.getAbsolutePath());
            System.out.println("檔案構造路徑:"+f.getPath());
            System.out.println("檔名稱:"+f.getName());
            System.out.println("檔案長度:"+f.length()+"位元組");
    
            File f2 = new File("d:/aaa");     
            System.out.println("目錄絕對路徑:"+f2.getAbsolutePath());
            System.out.println("目錄構造路徑:"+f2.getPath());
            System.out.println("目錄名稱:"+f2.getName());
            System.out.println("目錄長度:"+f2.length());
        }
    }
    輸出結果:
    檔案絕對路徑:d:\aaa\bbb.java
    檔案構造路徑:d:\aaa\bbb.java
    檔名稱:bbb.java
    檔案長度:636位元組
    
    目錄絕對路徑:d:\aaa
    目錄構造路徑:d:\aaa
    目錄名稱:aaa
    目錄長度:4096
API中說明:length(),表示檔案的長度。但是File物件表示目錄,則返回值未指定。

絕對路徑和相對路徑

  • 絕對路徑:從磁碟機代號開始的路徑,這是一個完整的路徑。
  • 相對路徑:相對於專案目錄的路徑,這是一個便捷的路徑,開發中經常使用。
public class FilePath {
    public static void main(String[] args) {
          // D盤下的bbb.java檔案
        File f = new File("D:\\bbb.java");
        System.out.println(f.getAbsolutePath());
          
        // 專案下的bbb.java檔案
        File f2 = new File("bbb.java");
        System.out.println(f2.getAbsolutePath());
    }
}
輸出結果:
D:\bbb.java
D:\idea_project_test4\bbb.java

判斷功能的方法

  • public boolean exists() :此File表示的檔案或目錄是否實際存在。
  • public boolean isDirectory() :此File表示的是否為目錄。
  • public boolean isFile() :此File表示的是否為檔案。

方法演示,程式碼如下:

public class FileIs {
    public static void main(String[] args) {
        File f = new File("d:\\aaa\\bbb.java");
        File f2 = new File("d:\\aaa");
          // 判斷是否存在
        System.out.println("d:\\aaa\\bbb.java 是否存在:"+f.exists());
        System.out.println("d:\\aaa 是否存在:"+f2.exists());
          // 判斷是檔案還是目錄
        System.out.println("d:\\aaa 檔案?:"+f2.isFile());
        System.out.println("d:\\aaa 目錄?:"+f2.isDirectory());
    }
}
輸出結果:
d:\aaa\bbb.java 是否存在:true
d:\aaa 是否存在:true
d:\aaa 檔案?:false
d:\aaa 目錄?:true

建立刪除功能的方法

  • public boolean createNewFile() :當且僅當具有該名稱的檔案尚不存在時,建立一個新的空檔案。
  • public boolean delete() :刪除由此File表示的檔案或目錄。
  • public boolean mkdir() :建立由此File表示的目錄。
  • public boolean mkdirs() :建立由此File表示的目錄,包括任何必需但不存在的父目錄。

方法演示,程式碼如下:

public class FileCreateDelete {
    public static void main(String[] args) throws IOException {
        // 檔案的建立
        File f = new File("aaa.txt");
        System.out.println("是否存在:"+f.exists()); // false
        System.out.println("是否建立:"+f.createNewFile()); // true
        System.out.println("是否存在:"+f.exists()); // true
        
         // 目錄的建立
          File f2= new File("newDir");    
        System.out.println("是否存在:"+f2.exists());// false
        System.out.println("是否建立:"+f2.mkdir());    // true
        System.out.println("是否存在:"+f2.exists());// true

        // 建立多級目錄
          File f3= new File("newDira\\newDirb");
        System.out.println(f3.mkdir());// false
        File f4= new File("newDira\\newDirb");
        System.out.println(f4.mkdirs());// true
      
          // 檔案的刪除
           System.out.println(f.delete());// true
      
          // 目錄的刪除
        System.out.println(f2.delete());// true
        System.out.println(f4.delete());// false
    }
}
API中說明:delete方法,如果此File表示目錄,則目錄必須為空才能刪除。

2.4 目錄的遍歷

  • public String[] list() :返回一個String陣列,表示該File目錄中的所有子檔案或目錄。
  • public File[] listFiles() :返回一個File陣列,表示該File目錄中的所有的子檔案或目錄。
public class FileFor {
    public static void main(String[] args) {
        File dir = new File("d:\\java_code");
      
          //獲取當前目錄下的檔案以及資料夾的名稱。
        String[] names = dir.list();
        for(String name : names){
            System.out.println(name);
        }
        //獲取當前目錄下的檔案以及資料夾物件,只要拿到了檔案物件,那麼就可以獲取更多資訊
        File[] files = dir.listFiles();
        for (File file : files) {
            System.out.println(file);
        }
    }
}

小貼士:

呼叫listFiles方法的File物件,表示的必須是實際存在的目錄,否則返回null,無法進行遍歷。

2.5 綜合練習

練習1:建立資料夾

​ 在當前模組下的aaa資料夾中建立一個a.txt檔案

程式碼實現:

public class Test1 {
    public static void main(String[] args) throws IOException {
        //需求:在當前模組下的aaa資料夾中建立一個a.txt檔案

        //1.建立a.txt的父級路徑
        File file = new File("myfile\\aaa");
        //2.建立父級路徑
        //如果aaa是存在的,那麼此時建立失敗的。
        //如果aaa是不存在的,那麼此時建立成功的。
        file.mkdirs();
        //3.拼接父級路徑和子級路徑
        File src = new File(file,"a.txt");
        boolean b = src.createNewFile();
        if(b){
            System.out.println("建立成功");
        }else{
            System.out.println("建立失敗");
        }
    }
}
練習2:查詢檔案(不考慮子資料夾)

​ 定義一個方法找某一個資料夾中,是否有以avi結尾的電影(暫時不需要考慮子資料夾)

程式碼示例:

public class Test2 {
    public static void main(String[] args) {
        /*需求:
             定義一個方法找某一個資料夾中,是否有以avi結尾的電影。
            (暫時不需要考慮子資料夾)
        */

        File file = new File("D:\\aaa\\bbb");
        boolean b = haveAVI(file);
        System.out.println(b);
    }
    /*
    * 作用:用來找某一個資料夾中,是否有以avi結尾的電影
    * 形參:要查詢的資料夾
    * 返回值:查詢的結果  存在true  不存在false
    * */
    public static boolean haveAVI(File file){// D:\\aaa
        //1.進入aaa資料夾,而且要獲取裡面所有的內容
        File[] files = file.listFiles();
        //2.遍歷陣列獲取裡面的每一個元素
        for (File f : files) {
            //f:依次表示aaa資料夾裡面每一個檔案或者資料夾的路徑
            if(f.isFile() && f.getName().endsWith(".avi")){
                return true;
            }
        }
        //3.如果迴圈結束之後還沒有找到,直接返回false
        return false;
    }
}

練習3:(考慮子資料夾)

​ 找到電腦中所有以avi結尾的電影。(需要考慮子資料夾)

程式碼示例:

public class Test3 {
    public static void main(String[] args) {
        /* 需求:
        找到電腦中所有以avi結尾的電影。(需要考慮子資料夾)


        套路:
            1,進入資料夾
            2,遍歷陣列
            3,判斷
            4,判斷

        */

        findAVI();

    }

    public static void findAVI(){
        //獲取本地所有的磁碟機代號
        File[] arr = File.listRoots();
        for (File f : arr) {
            findAVI(f);
        }
    }

    public static void findAVI(File src){//"C:\\
        //1.進入資料夾src
        File[] files = src.listFiles();
        //2.遍歷陣列,依次得到src裡面每一個檔案或者資料夾
        if(files != null){
            for (File file : files) {
                if(file.isFile()){
                    //3,判斷,如果是檔案,就可以執行題目的業務邏輯
                    String name = file.getName();
                    if(name.endsWith(".avi")){
                        System.out.println(file);
                    }
                }else{
                    //4,判斷,如果是資料夾,就可以遞迴
                    //細節:再次呼叫本方法的時候,引數一定要是src的次一級路徑
                    findAVI(file);
                }
            }
        }
    }
}

練習4:刪除多級資料夾

需求: 如果我們要刪除一個有內容的資料夾

   1.先刪除資料夾裡面所有的內容
       2.再刪除自己

程式碼示例:

public class Test4 {
    public static void main(String[] args) {
        /*
           刪除一個多級資料夾
           如果我們要刪除一個有內容的資料夾
           1.先刪除資料夾裡面所有的內容
           2.再刪除自己
        */

        File file = new File("D:\\aaa\\src");
        delete(file);

    }

    /*
    * 作用:刪除src資料夾
    * 引數:要刪除的資料夾
    * */
    public static void delete(File src){
        //1.先刪除資料夾裡面所有的內容
        //進入src
        File[] files = src.listFiles();
        //遍歷
        for (File file : files) {
            //判斷,如果是檔案,刪除
            if(file.isFile()){
                file.delete();
            }else {
                //判斷,如果是資料夾,就遞迴
                delete(file);
            }
        }
        //2.再刪除自己
        src.delete();
    }
}

練習5:統計大小

​ 需求:統計一個資料夾的總大小

程式碼示例:

public class Test5 {
    public static void main(String[] args) {
       /*需求:
            統計一個資料夾的總大小
      */


        File file = new File("D:\\aaa\\src");

        long len = getLen(file);
        System.out.println(len);//4919189
    }

    /*
    * 作用:
    *       統計一個資料夾的總大小
    * 引數:
    *       表示要統計的那個資料夾
    * 返回值:
    *       統計之後的結果
    *
    * 資料夾的總大小:
    *       說白了,資料夾裡面所有檔案的大小
    * */
    public static long getLen(File src){
        //1.定義變數進行累加
        long len = 0;
        //2.進入src資料夾
        File[] files = src.listFiles();
        //3.遍歷陣列
        for (File file : files) {
            //4.判斷
            if(file.isFile()){
                //我們就把當前檔案的大小累加到len當中
                len = len + file.length();
            }else{
                //判斷,如果是資料夾就遞迴
                len = len + getLen(file);
            }
        }
        return len;
    }
}

練習6:統計檔案個數

需求:統計一個資料夾中每種檔案的個數並列印。(考慮子資料夾)

        列印格式如下:
        txt:3個
        doc:4個
        jpg:6個

程式碼示例:

public class Test6 {
    public static void main(String[] args) throws IOException {
        /*
            需求:統計一個資料夾中每種檔案的個數並列印。(考慮子資料夾)
            列印格式如下:
            txt:3個
            doc:4個
            jpg:6個
        */
        File file = new File("D:\\aaa\\src");
        HashMap<String, Integer> hm = getCount(file);
        System.out.println(hm);
    }

    /*
    * 作用:
    *       統計一個資料夾中每種檔案的個數
    * 引數:
    *       要統計的那個資料夾
    * 返回值:
    *       用來統計map集合
    *       鍵:字尾名 值:次數
    *
    *       a.txt
    *       a.a.txt
    *       aaa(不需要統計的)
    *
    *
    * */
    public static HashMap<String,Integer> getCount(File src){
        //1.定義集合用來統計
        HashMap<String,Integer> hm = new HashMap<>();
        //2.進入src資料夾
        File[] files = src.listFiles();
        //3.遍歷陣列
        for (File file : files) {
            //4.判斷,如果是檔案,統計
            if(file.isFile()){
                //a.txt
                String name = file.getName();
                String[] arr = name.split("\\.");
                if(arr.length >= 2){
                    String endName = arr[arr.length - 1];
                    if(hm.containsKey(endName)){
                        //存在
                        int count = hm.get(endName);
                        count++;
                        hm.put(endName,count);
                    }else{
                        //不存在
                        hm.put(endName,1);
                    }
                }
            }else{
                //5.判斷,如果是資料夾,遞迴
                //sonMap裡面是子檔案中每一種檔案的個數
                HashMap<String, Integer> sonMap = getCount(file);
                //hm:  txt=1  jpg=2  doc=3
                //sonMap: txt=3 jpg=1
                //遍歷sonMap把裡面的值累加到hm當中
                Set<Map.Entry<String, Integer>> entries = sonMap.entrySet();
                for (Map.Entry<String, Integer> entry : entries) {
                    String key = entry.getKey();
                    int value = entry.getValue();
                    if(hm.containsKey(key)){
                        //存在
                        int count = hm.get(key);
                        count = count + value;
                        hm.put(key,count);
                    }else{
                        //不存在
                        hm.put(key,value);
                    }
                }
            }
        }
        return hm;
    }
}

相關文章