File類、遞迴
第一章 File類
1.1 概述
java.io.File
類是檔案和目錄路徑名的抽象表示,主要用於檔案和目錄的建立、查詢和刪除等操作。
1.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);
-
一個File物件代表硬碟中實際存在的一個檔案或者目錄。
-
1.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表示目錄,則目錄必須為空才能刪除。
1.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); } } }
第二章 遞迴
2.1 概述
-
遞迴:指在當前方法內呼叫自己的這種現象。
-
遞迴的分類:
-
遞迴分為兩種,直接遞迴和間接遞迴。
-
直接遞迴稱為方法自身呼叫自己。
-
間接遞迴可以A方法呼叫B方法,B方法呼叫C方法,C方法呼叫A方法。
-
-
注意事項:
-
遞迴一定要有條件限定,保證遞迴能夠停止下來,否則會發生棧記憶體溢位。
-
在遞迴中雖然有限定條件,但是遞迴次數不能太多。否則也會發生棧記憶體溢位。
-
構造方法,禁止遞迴
-
public class Demo01DiGui { public static void main(String[] args) { // a(); b(1); } /* * 3.構造方法,禁止遞迴 * 編譯報錯:構造方法是建立物件使用的,不能讓物件一直建立下去 */ public Demo01DiGui() { //Demo01DiGui(); } /* * 2.在遞迴中雖然有限定條件,但是遞迴次數不能太多。否則也會發生棧記憶體溢位。 * 4993 * Exception in thread "main" java.lang.StackOverflowError */ private static void b(int i) { System.out.println(i); //新增一個遞迴結束的條件,i==5000的時候結束 if(i==5000){ return;//結束方法 } b(++i); } /* * 1.遞迴一定要有條件限定,保證遞迴能夠停止下來,否則會發生棧記憶體溢位。 Exception in thread "main" * java.lang.StackOverflowError */ private static void a() { System.out.println("a方法"); a(); } }
2.2 遞迴累加求和
計算1 ~ n的和
分析:num的累和 = num + (num-1)的累和,所以可以把累和的操作定義成一個方法,遞迴呼叫。
實現程式碼:
public class DiGuiDemo { public static void main(String[] args) { //計算1~num的和,使用遞迴完成 int num = 5; // 呼叫求和的方法 int sum = getSum(num); // 輸出結果 System.out.println(sum); } /* 通過遞迴演算法實現. 引數列表:int 返回值型別: int */ public static int getSum(int num) { /* num為1時,方法返回1, 相當於是方法的出口,num總有是1的情況 */ if(num == 1){ return 1; } /* num不為1時,方法返回 num +(num-1)的累和 遞迴呼叫getSum方法 */ return num + getSum(num-1); } }
小貼士:遞迴一定要有條件限定,保證遞迴能夠停止下來,次數不要太多,否則會發生棧記憶體溢位。
2.3 遞迴求階乘
-
階乘:所有小於及等於該數的正整數的積。
n的階乘:n! = n * (n-1) *...* 3 * 2 * 1
推理得出:n! = n * (n-1)!
public class DiGuiDemo { //計算n的階乘,使用遞迴完成 public static void main(String[] args) { int n = 3; // 呼叫求階乘的方法 int value = getValue(n); // 輸出結果 System.out.println("階乘為:"+ value); } /* 通過遞迴演算法實現. 引數列表:int 返回值型別: int */ public static int getValue(int n) { // 1的階乘為1 if (n == 1) { return 1; } /* n不為1時,方法返回 n! = n*(n-1)! 遞迴呼叫getValue方法 */ return n * getValue(n - 1); } }
public class DiGuiDemo2 { public static void main(String[] args) { // 建立File物件 File dir = new File("D:\\aaa"); // 呼叫列印目錄方法 printDir(dir); } public static void printDir(File dir) { // 獲取子檔案和目錄 File[] files = dir.listFiles(); // 迴圈列印 /* 判斷: 當是檔案時,列印絕對路徑. 當是目錄時,繼續呼叫列印目錄的方法,形成遞迴呼叫. */ for (File file : files) { // 判斷 if (file.isFile()) { // 是檔案,輸出檔案絕對路徑 System.out.println("檔名:"+ file.getAbsolutePath()); } else { // 是目錄,輸出目錄絕對路徑 System.out.println("目錄:"+file.getAbsolutePath()); // 繼續遍歷,呼叫printDir,形成遞迴 printDir(file); } } } }
第三章 綜合案例
3.1 檔案搜尋
搜尋D:\aaa
目錄中的.java
檔案。
分析:
-
目錄搜尋,無法判斷多少級目錄,所以使用遞迴,遍歷所有目錄。
-
遍歷目錄時,獲取的子檔案,通過檔名稱,判斷是否符合條件。
程式碼實現:
public class DiGuiDemo3 { public static void main(String[] args) { // 建立File物件 File dir = new File("D:\\aaa"); // 呼叫列印目錄方法 printDir(dir); } public static void printDir(File dir) { // 獲取子檔案和目錄 File[] files = dir.listFiles(); // 迴圈列印 for (File file : files) { if (file.isFile()) { // 是檔案,判斷檔名並輸出檔案絕對路徑 if (file.getName().endsWith(".java")) { System.out.println("檔名:" + file.getAbsolutePath()); } } else { // 是目錄,繼續遍歷,形成遞迴 printDir(file); } } } }
3.2 檔案過濾器優化
java.io.FileFilter
是一個介面,是File的過濾器。 該介面的物件可以傳遞給File類的listFiles(FileFilter)
作為引數, 介面中只有一個方法。
boolean accept(File pathname)
:測試pathname是否應該包含在當前File目錄中,符合則返回true。
分析:
-
介面作為引數,需要傳遞子類物件,重寫其中方法。我們選擇匿名內部類方式,比較簡單。
-
accept
方法,引數為File,表示當前File下所有的子檔案和子目錄。保留住則返回true,過濾掉則返回false。保留規則:-
要麼是.java檔案。
-
要麼是目錄,用於繼續遍歷。
-
-
通過過濾器的作用,
listFiles(FileFilter)
返回的陣列元素中,子檔案物件都是符合條件的,可以直接列印。
程式碼實現:
public class DiGuiDemo4 { public static void main(String[] args) { File dir = new File("D:\\aaa"); printDir2(dir); } public static void printDir2(File dir) { // 匿名內部類方式,建立過濾器子類物件 File[] files = dir.listFiles(new FileFilter() { @Override public boolean accept(File pathname) { return pathname.getName().endsWith(".java")||pathname.isDirectory(); } }); // 迴圈列印 for (File file : files) { if (file.isFile()) { System.out.println("檔名:" + file.getAbsolutePath()); } else { printDir2(file); } } } }
3.3 Lambda優化
分析:FileFilter
是隻有一個方法的介面,因此可以用lambda表示式簡寫。
lambda格式:
()->{ }
程式碼實現:
public static void printDir3(File dir) { // lambda的改寫 File[] files = dir.listFiles(f ->{ return f.getName().endsWith(".java") || f.isDirectory(); }); // 迴圈列印 for (File file : files) { if (file.isFile()) { System.out.println("檔名:" + file.getAbsolutePath()); } else { printDir3(file); } } }