最近在紧张的学习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