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

时间: 2024-10-10 17:58:40

C#基础:用简单的文件管理程序来理解应用递归的相关文章

简单的文件管理程序练习

根据父级目录(存在session中)找到子文件,并显示如果要显示下级目录下的子文件 需要将session中的值变成下级目录的路径如果要返回上一级 需要将session中的值变为上级目录 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns

一个简单的文件管理程序

IEEE Spectrum 杂志发布了一年一度的编程语言排行榜,这也是他们发布的第四届编程语言 Top 榜. 据介绍,IEEE Spectrum 的排序是来自 10 个重要线上数据源的综合,例如 Stack Overflow.Twitter.Reddit.IEEE Xplore.GitHub.CareerBuilder 等,对 48 种语言进行排行. 与其他排行榜不同的是,IEEE Spectrum 可以让读者自己选择参数组合时的权重,得到不同的排序结果.考虑到典型的 Spectrum 读者需求

萌新向Python数据分析及数据挖掘 第一章 Python基础 第十节 文件和异常

第一章 Python基础 第十节 文件和异常 从文件中读取数据 读取文件.文件路径   1 filename = 'pi_digits.txt' #文件名取个代号 2 #读取整个文件 3 with open(filename) as file_object: 4 contents = file_object.read()# 给内容取个代号 5 print(contents.rstrip()) 6 #逐行读取 7 with open(filename) as file_object: 8 for

Python基础(8)--文件

文件可以通过调用open或file来打开,open通常比file更通用,因为file几乎都是为面向对象程序设计量身打造 本文地址:http://www.cnblogs.com/archimedes/p/python-file.html,转载请注明源地址. 打开文件 打开文件程序会调用内置的open函数,首先是外部名,接着就是处理模式. 常见的文件运算: 在任何情况下,Python程序中的文本文件采用字符串的形式,读取文本时会返回字符串形式的文本 从文件中读取的数据回到脚本时是一个字符串,所以如果

ios开发UI基础—Kvc简单介绍

一.KVC简单介绍 KVC key valued coding 键值编码 KVC通过键值间接编码 补充: 与KVC相对的时KVO,即key valued observer 键值观察.监听某一个模型的属性,只要模型属性的值一变化就通知你. 二.使用KVC 1.KVC基本使用介绍 (1)代码示例: 新建一个命令行项目,用以演示KVC的用法 完成之后为项目添加一个Person类. 为Person类添加两个属性(name和age),注意这两个属性的类型. 1 #import <Foundation/Fo

C#基础知识简单梳理

C#基础知识简单梳理 本文是转发博友的总结,方便自己以后随时温习: 1.值类型和引用类型 1.1堆和栈 简单的说值类型存放在堆栈上面,引用类型的数据存放在托管堆上面(它的引用地址却存放在堆栈上面)! 栈:它是一个内存数组,是一个先进后出的数据结构! 栈的特征:数据只能从栈顶进,从栈顶出! 堆:它是一个内存区域,可以分配大块区域存储某类型的数据,与栈不同的是它里面的数据可以任意排序和移除! 下面是园子的一张图,贴上来供大家参考啊! 问     题 值  类  型 引 用 类 型 这个类型分配在哪里

SpringMVC 基础教程 简单入门实例

SpringMVC 基础教程 简单入门实例 标签: Spring MVCspringmvcSpringMVC教程基础教程SpringMVC实例 2013-05-09 13:44 170403人阅读 评论(69) 收藏 举报  分类: Java(23)  Spring框架(3)  版权声明:本文为博主原创文章,未经博主允许不得转载. spring MVC 入门教程二: 一个简单的入门实例教程 该实例的源码和实例中的jar 源码:http://download.csdn.net/detail/swi

ASP.NET Core 动作结果 - ASP.NET Core 基础教程 - 简单教程,简单编程

原文:ASP.NET Core 动作结果 - ASP.NET Core 基础教程 - 简单教程,简单编程 ASP.NET Core 动作结果 前面的章节中,我们一直使用简单的 C# 类作为控制器. 虽然这些类不是从基类派生的,但仍然可以在 MVC 中使用这种方法. 当然了,对于控制器,但更常见的做法是从 Microsoft.AspNetCore.Mvc 命名空间中提供的控制器基类中派生控制器.本章中,我们将尝试这么做,并且学习动作结果 ( Action Results ). 动作结果 ( Act

ASP.NET Core 设置和初始化数据库 - ASP.NET Core 基础教程 - 简单教程,简单编程

原文:ASP.NET Core 设置和初始化数据库 - ASP.NET Core 基础教程 - 简单教程,简单编程 ASP.NET Core 设置和初始化数据库 上一章节中我们已经设置和配置好了 EF 框架服务,本章节我们就来学习如何使用 EF 框架设置和初始化数据库 初始化数据库 初始化数据库的方法之一是使用 EF 框架来创建数据库,仅仅需要两步就能完成 第一步,给我们的 HelloWorld 项目添加迁移 ( migration ) 代码 迁移代码是 C# 代码,用来在数据库系统中创建数据库