最近在緊張的學習C#,說實話對C#之前沒有太多的接觸過,只知道C#的特性與java很相似,接觸了之后才發現C#跟java相比區別不是很多,但它是一門實現程序能力比Java還要好的語言(僅代表個人觀點)。
有許多新手在學習編程語言的時候,都會在遞歸上面卡住,理解和應用起來會十分的吃力,所以我就自己嘗試用遞歸寫了一個很簡單很簡單很簡單的文件管理程序,說它簡單是因為他真的沒有什么難度,都是很底層的循環和遞歸,也就只有130多行代碼,只是希望能夠幫助大家理解應用遞歸。如果你一點編程基礎木有,那請不要直接來嘗試遞歸和各種循環,請一步步扎實的從頭學起。
這個很簡單很簡單很簡單的文件管理程序提供如下幾個功能:檢索用戶輸入路徑下文件的總數量;檢索用戶輸入路徑下文件夾的數量;檢索用戶輸入路徑下所有結尾與輸入字符匹配的文件數量。這么說可能有點兒抽象,先貼一張程序運行的結果圖片。
我分別使用這個小程序檢索了我C盤下Autodesk文件夾內的文件總數,文件夾總數和txt文件總數,最后退出程序。然后我來到了Autodesk文件夾,右鍵屬性了一下,證實數量確實是正確的。而至于txt的數量,我在文件夾窗口搜索欄輸入txt,一共182個結果,然而我一個一個數過了,有6個是開頭為txt的,所以176是準確無誤的。如果你想要讓我們代碼的功能編程包含txt這三個字符而不是以這三個字符結尾,只需要在后面進行簡單修改,這里先不贅述。
好了閑話不多說直接貼上代碼:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;//需要引入
using System.Threading;//需要引入namespace FilesManager
{class Program{//FilesNumber方法#regionstatic int FilesNumber(string path){int count = 0;try{var files = Directory.GetFiles(path);count = files.Length;var directories = Directory.GetDirectories(path);foreach (var direc in directories){count += FilesNumber(direc);}}catch (UnauthorizedAccessException exception){Console.WriteLine(exception.Message);}return count;}#endregion//DirectoriesNumber方法#regionstatic int DirectoriesNumber(string path){int count = 0;try{var directories = Directory.GetDirectories(path);count = directories.Length;foreach (var direc in directories){count += DirectoriesNumber(direc);}}catch (UnauthorizedAccessException exception){Console.WriteLine(exception.Message);}return count;}#endregion//FindExtension方法#regionstatic int FindExtension(string path, string extension){int count = 0;try{var files = Directory.GetFiles(path);foreach (var file in files){if (file.ToLower().EndsWith(extension)) count++;}var directories = Directory.GetDirectories(path);foreach (var direc in directories){count += FindExtension(direc, extension);}}catch (UnauthorizedAccessException exception){Console.WriteLine(exception.Message);}return count;}#endregion//Main方法#regionstatic void Main(string[] args){string path, extension, order;Thread.Sleep(1200);Console.WriteLine("程序開始,Designed By Mr.Losers");Thread.Sleep(1200);Console.WriteLine("特別鳴謝:何掌柜的");Thread.Sleep(1200);Console.WriteLine();Console.Write("計算路徑下文件數量請輸入0\n計算路徑下文件夾子數請輸入1\n");Console.Write("搜索路徑下文件名匹配數量請輸入2\n退出程序請輸入q\n");do{order = Console.ReadLine();if (order == "0"){Console.Write("文件管理系統已經就緒!\n請輸入你要查找的路徑:\n");path = Console.ReadLine();Console.WriteLine("該路徑下文件總數為:{0}", FilesNumber(path));order = Console.ReadLine();}if (order == "1"){Console.Write("文件管理系統已經就緒!\n請輸入你要查找的路徑:\n");path = Console.ReadLine();Console.WriteLine("該路徑下文件夾總數為:{0}", DirectoriesNumber(path));order = Console.ReadLine();}if (order == "2"){Console.Write("文件管理系統已經就緒!\n請輸入你要查找的路徑:\n");path = Console.ReadLine();Console.WriteLine("請輸入你想要匹配的文件名稱:");extension = Console.ReadLine();Console.WriteLine("符合名稱的文件總數為:{0}", FindExtension(path, extension));order = Console.ReadLine();}if (order == "q")break;else{Console.WriteLine("輸入錯誤請重新輸入:");}}while (true);Console.Write("Thanks for using!");Thread.Sleep(2000);}#endregion}
}
貼完代碼后,來簡單說明一下里面包含的東西。
首先要說幾個點:
第一個是在代碼中我使用了多次var,var是C#中很方便一種用法,讓編譯器自動判斷類型。比如這里的Directory.GetFiles(path);
返回的是一個string類型的數組,是包含path路徑下的每個文件的路徑數組。var files = Directory.GetFiles()相當于string [] files = Directory.GetFiles(path)
第二個是預處理指令,#region和#endregion,方便管理代碼,收起一塊區域內的代碼
第三個是try catch語句,在本程序中我們每一個文件搜索的方法都使用了該語句,因為無論是C盤還是D盤等盤符都會有文件我們是沒有訪問權限的,所以我們要catch UnauthorizedAccessException,并且把此exception的信息打印出來,這樣一來我們可以知道那些文件沒有被進一步訪問,二來程序不會因為exception而中斷。
第四個是我們在開始需要引入兩個命名空間,因為我們用到的方法Thread.Sleep()需要引入System.Threading;用到的GetFiles()和GetDirectories()需要引入System.IO;
下面我們按照順序來看代碼,先來講FilesNumber方法,三個方法都使用了遞歸的思想,此方法需要傳入一個形參path,既搜索的路徑。count為計數器,計算文件的個數。
首先對我們傳入路徑path中的所有文件計數,所以count = files.Length,然后取出path中所有的directory,也就是可以繼續向下探索的文件夾;接下來是很重要的一步——遞歸,對每個path中取出的directory再繼續執行本方法,并與當前count相加得到新的count數值,層層向下,直到不存在可以繼續向下探索的文件夾為止。
在方法中調用自己是遞歸的基本思路。我們假設path下有10個文件,其中有3個文件夾path1,path2,path3,那實際上這段代碼的執行過程是:count(path)= path路徑下的文件數量+count(path1)+country(path2)+count(path3),然后path1,path2,path3內還有文件和文件夾,于是分解仍在繼續。
舉一個數學例子幫助大家理解:
128 = 64 + 64 = 64 + (32 +32)= 64 + ((16+16)+(16+16))= 64 + (((8+8)+(8+8))+((8+8)+(8+8))),雖然不完全一樣,
但道理是差不多的,都是一個層層分解的過程。我已經用生命在解釋了,還是沒懂得請多思考思考,或者另謀高就把。。。。
解釋完了FilesNumber的話,DirectoriesNumnber是比FilesNumber還要簡單的同樣使用了遞歸的方法,這就略過了。
FindExtension方法只是做了些許的改變,首先方法傳入兩個參數,一個路徑path,一個匹配的擴展名extension,這里注意我使用的兩個方法,ToLower方法確保了大小寫的匹配文件都可以找到,EndsWith()是后端匹配,當然我們也可以使用StartWith()和Contains(),如果你搜索的文件數量很少,并且我們還可以找到文件后,輸入它當前的路徑,這些就交給讀者自己去修改吧,其實是比較簡單的,我為了保證程序的簡潔就沒有輸出路徑,100多條路徑一下輸出出來也是挺痛苦的。
接下來來到Main方法,注意Java中Main方法都是小寫的main,而C#中需要大寫。
Main方法的前半部分都是定義和輸出使用方法。因為我有一點兒輕微的強迫癥,認為輸出時加入延遲會讓人感覺更加舒服,并且會認真看屏幕上出現的字。所以我加入了Sleep方法,我一開始設定的是Sleep2000毫秒你敢信。。。。
在輸出文字后的do while循環才是程序的主體。其實完全可以改用while,只是不知道為啥我寫的時候,用了個do while,你會發現我后面while的條件是true,也就是他會一直執行,直到用戶輸入Q后break出來。。。。。
這個循環中首先會要求你輸入,根據前面提示用戶會知道輸入0、1、2、q來選擇功能,然后程序會根據用戶輸入不同的字符來執行不通的功能即調用不同的方法,執行之后立刻重置,以準備下一次使用。因為輸入的是字符串,我就沒有轉換為int類型然后使用switch語句。
其實現在仔細看看這個程序真的是很簡單很簡單很簡單的,最簡單的遞歸,最簡單的循環,所以我們不得不贊嘆代碼真的是很神奇的東西,我到現在還記得前兩天把這個小東西給不懂編程的女票何掌柜看的時候她竟然以為這個小程序很強大,能賣錢,也是秀逗了。
最后還是希望能夠幫到大家,C#真的是一門很好的語言。
另:如果大家發現了一些錯誤或者有更好的改進還請不吝賜教,請郵箱、私信或者微博聯系我。
2015.4.5 15:39
By Mr.Losers