File類、遞歸

內(nèi)容預(yù)覽

  • File類
  • 遞歸

File類

1.1 概述

java.io.File 類是文件和目錄路徑名的抽象表示,主要用于文件和目錄的創(chuàng)建、查找和刪除等操作。

1.2 構(gòu)造方法

  • public File(String pathname) :通過將給定的路徑名字符串轉(zhuǎn)換為抽象路徑名來創(chuàng)建新的 File實例。
  • public File(String parent, String child) :從父路徑名字符串和子路徑名字符串創(chuàng)建新的 File實例。
  • public File(File parent, String child) :從父抽象路徑名和子路徑名字符串創(chuàng)建新的 File實例。
  • 構(gòu)造舉例,代碼如下:
// 文件路徑名
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對象的創(chuàng)建。

1.3 常用方法

獲取功能的方法

  • public String getAbsolutePath() :返回此File的絕對路徑名字符串。

  • public String getPath() :將此File轉(zhuǎn)換為路徑名字符串。

  • 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("文件構(gòu)造路徑:"+f.getPath());
            System.out.println("文件名稱:"+f.getName());
            System.out.println("文件長度:"+f.length()+"字節(jié)");
    
            File f2 = new File("d:/aaa");     
            System.out.println("目錄絕對路徑:"+f2.getAbsolutePath());
            System.out.println("目錄構(gòu)造路徑:"+f2.getPath());
            System.out.println("目錄名稱:"+f2.getName());
            System.out.println("目錄長度:"+f2.length());
        }
    }
    輸出結(jié)果:
    文件絕對路徑:d:\aaa\bbb.java
    文件構(gòu)造路徑:d:\aaa\bbb.java
    文件名稱:bbb.java
    文件長度:636字節(jié)
    
    目錄絕對路徑:d:\aaa
    目錄構(gòu)造路徑:d:\aaa
    目錄名稱:aaa
    目錄長度:4096
    

API中說明:length(),表示文件的長度。但是File對象表示目錄,則返回值未指定。

絕對路徑和相對路徑

  • 絕對路徑:從盤符開始的路徑,這是一個完整的路徑。
  • 相對路徑:相對于項目目錄的路徑,這是一個便捷的路徑,開發(fā)中經(jīng)常使用。
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());
    }
}
輸出結(jié)果:
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());
    }
}
輸出結(jié)果:
d:\aaa\bbb.java 是否存在:true
d:\aaa 是否存在:true
d:\aaa 文件?:false
d:\aaa 目錄?:true

創(chuàng)建刪除功能的方法

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

方法演示,代碼如下:

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

        // 創(chuàng)建多級目錄
        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表示目錄,則目錄必須為空才能刪除。

1.4 目錄的遍歷

  • public String[] list() :返回一個String數(shù)組,表示該File目錄中的所有子文件或目錄。
  • public File[] listFiles() :返回一個File數(shù)組,表示該File目錄中的所有的子文件或目錄。
public class FileFor {
    public static void main(String[] args) {
        File dir = new File("d:\\java_code");
      
        //獲取當(dāng)前目錄下的文件以及文件夾的名稱。
        String[] names = dir.list();
        for(String name : names){
            System.out.println(name);
        }
        //獲取當(dāng)前目錄下的文件以及文件夾對象,只要拿到了文件對象,那么就可以獲取更多信息
        File[] files = dir.listFiles();
        for (File file : files) {
            System.out.println(file);
        }
    }
}

調(diào)用listFiles方法的File對象,表示的必須是實際存在的目錄,否則返回null,無法進行遍歷。


遞歸

2.1 概述

  • 遞歸:指在當(dāng)前方法內(nèi)調(diào)用自己的這種現(xiàn)象。

  • 遞歸的分類:

    • 遞歸分為兩種,直接遞歸和間接遞歸。
    • 直接遞歸稱為方法自身調(diào)用自己。
    • 間接遞歸可以A方法調(diào)用B方法,B方法調(diào)用C方法,C方法調(diào)用A方法。
  • 注意事項

    • 遞歸一定要有條件限定,保證遞歸能夠停止下來,否則會發(fā)生棧內(nèi)存溢出。
    • 在遞歸中雖然有限定條件,但是遞歸次數(shù)不能太多。否則也會發(fā)生棧內(nèi)存溢出。
    • 構(gòu)造方法,禁止遞歸
遞歸導(dǎo)致棧內(nèi)存溢出原理.png
public class Demo01DiGui {
    public static void main(String[] args) {
        // a();
        b(1);
    }
    
    /*
     * 3.構(gòu)造方法,禁止遞歸
     * 編譯報錯:構(gòu)造方法是創(chuàng)建對象使用的,不能讓對象一直創(chuàng)建下去
     */
    public Demo01DiGui() {
        //Demo01DiGui();
    }


    /*
     * 2.在遞歸中雖然有限定條件,但是遞歸次數(shù)不能太多。否則也會發(fā)生棧內(nèi)存溢出。
     * 4993
     *  Exception in thread "main" java.lang.StackOverflowError
     */
    private static void b(int i) {
        System.out.println(i);
        //添加一個遞歸結(jié)束的條件,i==5000的時候結(jié)束
        if(i==5000){
            return;//結(jié)束方法
        }
        b(++i);
    }

    /*
     * 1.遞歸一定要有條件限定,保證遞歸能夠停止下來,否則會發(fā)生棧內(nèi)存溢出。 Exception in thread "main"
     * java.lang.StackOverflowError
     */
    private static void a() {
        System.out.println("a方法");
        a();
    }
}

2.2 遞歸累加求和

計算1 ~ n的和

分析:num的累和 = num + (num-1)的累和,所以可以把累和的操作定義成一個方法,遞歸調(diào)用。

實現(xiàn)代碼

public class DiGuiDemo {
    public static void main(String[] args) {
        //計算1~num的和,使用遞歸完成
        int num = 5;
        // 調(diào)用求和的方法
        int sum = getSum(num);
        // 輸出結(jié)果
        System.out.println(sum);
        
    }
    /*
      通過遞歸算法實現(xiàn).
      參數(shù)列表:int 
      返回值類型: int 
    */
    public static int getSum(int num) {
        /* 
           num為1時,方法返回1,
           相當(dāng)于是方法的出口,num總有是1的情況
        */
        if(num == 1){
            return 1;
        }
        /*
          num不為1時,方法返回 num +(num-1)的累和
          遞歸調(diào)用getSum方法
        */
        return num + getSum(num-1);
    }
}

代碼執(zhí)行圖解

遞歸一定要有條件限定,保證遞歸能夠停止下來,次數(shù)不要太多,否則會發(fā)生棧內(nèi)存溢出。

2.3 遞歸求階乘

  • 階乘:所有小于及等于該數(shù)的正整數(shù)的積。
n的階乘:n! = n * (n-1) *...* 3 * 2 * 1 

分析:這與累和類似,只不過換成了乘法運算,學(xué)員可以自己練習(xí),需要注意階乘值符合int類型的范圍。

推理得出:n! = n * (n-1)!

代碼實現(xiàn)

public class DiGuiDemo {
    //計算n的階乘,使用遞歸完成
    public static void main(String[] args) {
        int n = 3;
        // 調(diào)用求階乘的方法
        int value = getValue(n);
        // 輸出結(jié)果
        System.out.println("階乘為:"+ value);
    }
    /*
      通過遞歸算法實現(xiàn).
      參數(shù)列表:int 
      返回值類型: int 
    */
    public static int getValue(int n) {
        // 1的階乘為1
        if (n == 1) {
            return 1;
        }
        /*
          n不為1時,方法返回 n! = n*(n-1)!
          遞歸調(diào)用getValue方法
        */
        return n * getValue(n - 1);
    }
}

2.4 遞歸打印多級目錄

分析:多級目錄的打印,就是當(dāng)目錄的嵌套。遍歷之前,無從知道到底有多少級目錄,所以我們還是要使用遞歸實現(xiàn)。

遞歸遍歷多級目錄.png

代碼實現(xiàn)

public class DiGuiDemo2 {
    public static void main(String[] args) {
        // 創(chuàng)建File對象
        File dir  = new File("D:\\aaa");
        // 調(diào)用打印目錄方法
        printDir(dir);
    }

    public static void  printDir(File dir) {
        // 獲取子文件和目錄
        File[] files = dir.listFiles();
        // 循環(huán)打印
        /*
          判斷:
          當(dāng)是文件時,打印絕對路徑.
          當(dāng)是目錄時,繼續(xù)調(diào)用打印目錄的方法,形成遞歸調(diào)用.
        */
        for (File file : files) {
            // 判斷
            if (file.isFile()) {
                // 是文件,輸出文件絕對路徑
                System.out.println("文件名:"+ file.getAbsolutePath());
            } else {
                // 是目錄,輸出目錄絕對路徑
                System.out.println("目錄:"+file.getAbsolutePath());
                // 繼續(xù)遍歷,調(diào)用printDir,形成遞歸
                printDir(file);
            }
        }
    }
}

綜合案例

3.1 文件搜索

搜索D:\aaa 目錄中的.java 文件。

分析

  1. 目錄搜索,無法判斷多少級目錄,所以使用遞歸,遍歷所有目錄。
  2. 遍歷目錄時,獲取的子文件,通過文件名稱,判斷是否符合條件。

代碼實現(xiàn)

public class DiGuiDemo3 {
    public static void main(String[] args) {
        // 創(chuàng)建File對象
        File dir  = new File("D:\\aaa");
        // 調(diào)用打印目錄方法
        printDir(dir);
    }

    public static void printDir(File dir) {
        // 獲取子文件和目錄
        File[] files = dir.listFiles();
        
        // 循環(huán)打印
        for (File file : files) {
            if (file.isFile()) {
                // 是文件,判斷文件名并輸出文件絕對路徑
                if (file.getName().endsWith(".java")) {
                    System.out.println("文件名:" + file.getAbsolutePath());
                }
            } else {
                // 是目錄,繼續(xù)遍歷,形成遞歸
                printDir(file);
            }
        }
    }
}

3.2 文件過濾器優(yōu)化

java.io.FileFilter是一個接口,是File的過濾器。 該接口的對象可以傳遞給File類的listFiles(FileFilter) 作為參數(shù), 接口中只有一個方法。

boolean accept(File pathname) :測試pathname是否應(yīng)該包含在當(dāng)前File目錄中,符合則返回true。

分析

  1. 接口作為參數(shù),需要傳遞子類對象,重寫其中方法。我們選擇匿名內(nèi)部類方式,比較簡單。
  2. accept方法,參數(shù)為File,表示當(dāng)前File下所有的子文件和子目錄。保留住則返回true,過濾掉則返回false。保留規(guī)則:
    1. 要么是.java文件。
    2. 要么是目錄,用于繼續(xù)遍歷。
  3. 通過過濾器的作用,listFiles(FileFilter)返回的數(shù)組元素中,子文件對象都是符合條件的,可以直接打印。
FileFilter過濾器的原理.png

代碼實現(xiàn):

public class DiGuiDemo4 {
    public static void main(String[] args) {
        File dir = new File("D:\\aaa");
        printDir2(dir);
    }
  
    public static void printDir2(File dir) {
        // 匿名內(nèi)部類方式,創(chuàng)建過濾器子類對象
        File[] files = dir.listFiles(new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                return pathname.getName().endsWith(".java")||pathname.isDirectory();
            }
        });
        // 循環(huán)打印
        for (File file : files) {
            if (file.isFile()) {
                System.out.println("文件名:" + file.getAbsolutePath());
            } else {
                printDir2(file);
            }
        }
    }
}      

3.3 Lambda優(yōu)化

分析:FileFilter是只有一個方法的接口,因此可以用lambda表達式簡寫。

lambda格式:

()->{ }

代碼實現(xiàn):

public static void printDir3(File dir) {
    // lambda的改寫
    File[] files = dir.listFiles(f ->{ 
        return f.getName().endsWith(".java") || f.isDirectory(); 
    });
    
    // 循環(huán)打印
    for (File file : files) {
        if (file.isFile()) {
            System.out.println("文件名:" + file.getAbsolutePath());
        } else {
            printDir3(file);
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容