標籤:c# 基礎 遞迴
最近在緊張的學習C#,說實話對C#之前沒有太多的接觸過,只知道C#的特性與java很相似,接觸了之後才發現C#跟java相比區別不是很多,但它是一門實現程式能力比Java還要好的語言(僅代表個人觀點)。
有許多新手在學習程式設計語言的時候,都會在遞迴上面卡住,理解和應用起來會十分的吃力,所以我就自己嘗試用遞迴寫了一個很簡單很簡單很簡單的檔案管理程式,說它簡單是因為他真的沒有什麼難度,都是很底層的迴圈和遞迴,也就只有130多行代碼,只是希望能夠協助大家理解應用遞迴。如果你一點編程基礎木有,那請不要直接來嘗試遞迴和各種迴圈,請一步步紮實的從頭學起。
這個很簡單很簡單很簡單的檔案管理程式提供如下幾個功能:檢索使用者輸入路徑下檔案的總數量;檢索使用者輸入路徑下檔案夾的數量;檢索使用者輸入路徑下所有結尾與輸入字元匹配的檔案數量。這麼說可能有點兒抽象,先貼一張程式啟動並執行結果圖片。
我分別使用這個小程式檢索了我C盤下Autodesk檔案夾內的檔案總數,檔案夾總數和txt檔案總數,最後退出程式。然後我來到了Autodesk檔案夾,右鍵屬性了一下,證實數量確實是正確的。而至於txt的數量,我在檔案夾視窗搜尋欄輸入txt,一共182個結果,然而我一個一個數過了,有6個是開頭為txt的,所以176是準確無誤的。如果你想要讓我們代碼的功能編程包含txt這三個字元而不是以這三個字元結尾,只需要在後面進行簡單修改,這裡先不贅述。
好了閑話不多說直接貼上代碼:
程式名為:FilesManager
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方法 #region static 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方法 #region static 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方法 #region static 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方法 #region static 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
C#基礎:用簡單的檔案管理程式來理解應用遞迴