C# 基础知识系列- 17 实战篇 编写一个小工具(1)
0. 前言
这是对C# 基础系列的一个总结,现在我们利用之前学到的知识做一个小小的工具来给我们使用。
如果有看过IO篇的小伙伴,应该有印象。当时我提过一个场景描述,我们在平时使用系统的时候,经常会为了找某个文件的位置而烦恼。那么我们现在尝试写一个控制台程序来帮助我们找文件的具体位置。
1. 分析
好,大家应该初步了解了需求内容。然后让我们来做一个简单的需求分析:
- 简单分析一下需求包括哪些功能点
- 规划各个功能点的实现方式
嗯,理论上讲还有一大堆的步骤,但因为是个练手的小项目就不扯那么多没用的了。简单来讲就是,分两步:
- 抓取系统可以访问的所有文件,并保存其全路径
- 根据输入的参数查询文件的全路径
需求分析完了,然后寻找可以实现的技术,我们现有的技术有IO、文件/路径操作、任务模式等技术,那么可以供我们选择的技术一目了然了:通过文件/目录/路径API访问所有的文件目录,使用字典保存,然后使用Linq查询文件所在目录。
OK,需求分析完了,技术也确认了。那么我们现在开始吧,小伙伴们跟紧了哦,车速不快的。
2. 开始
这里简单演示一下如何用Rider和VSCode、Visual Studio2019创建项目。
2.1. 创建一个名为 FileFinder的项目
a.使用Rider:
点击箭头所指方向:
先在左侧选择Console Application,然后修改 Project name,最后修改 Solution Directory为自己的目录:
然后点击 Create,创建完成结果如下:
Rider创建项目的步骤在Windows、Linux、Mac三个系统都是一样的。
b. 使用VS Code创建项目
使用VS Code创建项目与Rider和Visual Studio有所不同,步骤比较繁琐:
先在合适的文件夹下创建一个fileFinder目录,并在fileFinder目录下打开命令行,输入以下命令:
dotnet new sln -n fileFinder # 创建一个名为 fileFinder 的解决方案
dotnet new console -n fileFinder # 创建一个名为 fileFinder的控制台程序
dotnet sln add fileFinder # 把 fileFinder的项目添加到fileFinder的解决方案里
最终结果应该是这样的:
c.使用 Visual Studio
选择【创建新项目】
注意框住地方的选择,选控制台程序,然后点击下一步
填写项目名称、路径,点击创建
2.2 开始编写程序
现在我们创建完成了一个项目,然后可以开始编写我们的程序了。
首先创建一个遍历所有目录的方法:
public static Dictionary<string,List<string>> OverDirectories()
{
//
return null;
}
现在我们有一个问题,因为Windows的特殊性,目录结构分为了磁盘:\文件夹这种形式,我们没法通过设置一个根目录去遍历,这时候就要借助一下官方文档了。通过查阅API,我们发现一个类:
public sealed class DriveInfo : System.Runtime.Serialization.ISerializable//提供对有关驱动器的信息的访问。
有一个方法:
public static System.IO.DriveInfo[] GetDrives ();// 检索计算机上的所有逻辑驱动器的驱动器名称。
再看一下属性:
public string Name { get; }// 获取驱动器的名称,如 C:\。
public System.IO.DirectoryInfo RootDirectory { get; }// 获取驱动器的根目录。
初步查看满足我们的需要,先在Program.cs的头添加命名空间引用:
using System.IO;
表示在这个代码文件中会使用这个命名空间的类或者结构体等元素。
在项目中编写一个方法:
public static void GetDrivers()
{
var drives = DriveInfo.GetDrives();
foreach(var drive in drives)
{
Console.WriteLine($"驱动器名称:{drive.Name}:\t {drive.RootDirectory}");
}
}
然后修改Main方法为:
static void Main(string[] args)
{
GetDrivers();
}
运行程序,下图是Linux系统的打印结果:(Rider/Visual Studio的运行程序快捷键是F5)
经过完美符合我们的需求,修改GetDrivers方法,使其可以返回所有驱动器的根目录:
先引入以下命名空间的引用:
using System.Linq;// Linq的支持
using System.Collections.Generic;//泛型集合的支持
修改方法如下:
public static List<DirectoryInfo> GetDrivers()
{
var drives = DriveInfo.GetDrives();
return drives.Select(p=>p.RootDirectory).ToList();
}
然后回到方法OverDirectories里,先获取所有的驱动器,遍历所有驱动器下的所有目录和文件,之后对遍历结果归类:
修改OverrDirectories方法:
public static Dictionary<string,List<string>> OverDirectories(DirectoryInfo rootDirectory)
{
var dict = new Dictionary<string, List<string>>();// 创建一个保存数据的 字典类型
foreach(var file in rootDirectory.EnumerateFiles()) //枚举当前目录下的所有文件
{
var key = Path.GetFileNameWithoutExtension(file.Name); //获取无扩展名的文件名
if(!dict.ContainsKey(key)) //检查dict是否存放过 文件名,如果没有,则创建一个列表,如果有则在列表中添加一条文件的全路径
{
dict[key] = new List<string>();
}
dict[key].Add(file.FullName);
}
// 枚举当前目录的子目录,递归调用该方法
var dirs = rootDirectory.EnumerateDirectories().Select(OverDirectories);
foreach(var dir in dirs)//处理返回的字典枚举,将数据合并到当前dict变量中
{
foreach(var key in dir.Keys)
{
if(!dict.ContainsKey(key))
{
dict[key] = new List<string>();
}
dict[key].AddRange(dir[key]);
}
}
// 返回结果
return dict;
}
我们简单测试一下,修改Main方法:
static void Main(string[] args)
{
var drivers = GetDrivers();
var results = OverDirectories(drivers[0]);
Console.WriteLine(results);
}
嗯,如果不出意外的话,你应该能得到类似如下的提示:
这是因为在系统中(不管哪种系统)会有一些文件或者目录是我们没有权限访问的,这时候就必须用try/catch处理这些没有访问权限的目录和文件。因为我们平时使用不会 把文件放到这些目录下面,所以我们可以简单的略过这些目录。
同时观察一下,GetDrivers 返回的是一组DirectoryInfo实例,而OverDirectories每次处理一个目录,然后返回一个字典集合,所以我们需要整合这些集合,但我们在OverDirectories里编写过相似的代码,为了减少重复代码的编写,提取这部分代码为一个方法:
public static Dictionary<string,List<string>> Concat(params Dictionary<string,List<string>>[] dicts)
{
var dict = new Dictionary<string,List<string>>();
foreach(var dir in dicts)
{
foreach(var key in dir.Keys)
{
if(!dict.ContainsKey(key))
{
dict[key] = new List<string>();
}
dict[key].AddRange(dir[key]);
}
}
return dict;
}
params 是C#可变参数列表关键字,声明方式: params T[] values。表示方法可以接收任意个T类型的参数,方法中接到的是一个数组
继续改造 OverDirectories方法,增加异常处理:
public static Dictionary<string,List<string>> OverDirectories(DirectoryInfo rootDirectory)
{
var dict = new Dictionary<string, List<string>>();
IEnumerable<FileInfo> files = new List<FileInfo>();
try
{
files = rootDirectory.EnumerateFiles();
}
catch(Exception e)
{
Console.WriteLine($"错误信息:{e}");//打印错误信息
}
foreach(var file in files)
{
var key = Path.GetFileNameWithoutExtension(file.Name);
if(!dict.ContainsKey(key))
{
dict[key] = new List<string>();
}
dict[key].Add(file.FullName);
}
try
{
var dicts = rootDirectory.EnumerateDirectories().Select(OverDirectories);
return Concat(dicts.Append(dict).ToArray());
}
catch (System.Exception e)
{
Console.WriteLine($"错误信息:{e}");//打印错误信息
}
return dict;
}
最后修改 Main方法,使其支持使用用户输入的字符串进行查询:
static void Main(string[] args)
{
var drivers = GetDrivers();
var results = Concat(drivers.Select(OverDirectories).ToArray());
Console.WriteLine("请输入要查询的文件名:");
var search = Console.ReadLine().Trim();
var keys = results.Keys.Where(p=>p.Contains(search));
foreach(var key in keys)
{
var list = results[key];
Console.WriteLine("查找到路径是:");
foreach(var path in list)
{
Console.WriteLine(path);
}
}
}
3. 总结
代码进行到这里了,可以说基本功能已经完成。如果有小伙伴尝试使用示例代码的话,可能会遇到各种问题,下一篇继续为大家在现有知识基础上做优化,让它成为一个真正意义上可以使用的小工具。
更多内容烦请关注我的博客《高先生小屋》
C# 基础知识系列- 17 实战篇 编写一个小工具(1)的更多相关文章
- C# 基础知识系列- 17 小工具优化
0. 前言 不知道有没有动手能力强的小伙伴照着上一篇的内容写过程序呢?如果有的话,应该会在使用的时候发现以下几个问题: 每次启动都需要经过漫长的时间去遍历磁盘里的文件目录 因为数据是用的字典保存的,所 ...
- C# 基础知识系列- 14 IO篇 流的使用
0. 前言 继续之前的C# IO流,在前几篇小短片中我们大概看了下C# 的基础IO也对文件.目录和路径的操作有了一定的了解.这一篇开始,给大家演示一下流的各种操作.以文件流为例,一起来看看如何操作吧. ...
- C# 基础知识系列- 14 IO篇 文件的操作 (3)
本篇继续前两篇内容,跟大家介绍一下Path类以及FileSystemInfo这个类的主要方法和属性. 上文提到,在<C# 基础知识系列-IO篇>之文件相关的内容完结之后,会带领大家开发一个 ...
- C# 基础知识系列- 14 IO篇之入门IO
0. 前言 在之前的章节中,大致介绍了C#中的一些基本概念.这篇我们将介绍一下C#的I/O操作,这将也是一个小连续剧.这是第一集,我们先来简单了解一下C#中的I/O框架. 1. 什么是I/O I/O ...
- C# 基础知识系列- 14 IO篇 文件的操作
0. 前言 本章节是IO篇的第二集,我们在上一篇中介绍了C#中IO的基本概念和一些基本方法,接下来我们介绍一下操作文件的方法.在编程的世界中,操作文件是一个很重要的技能. 1. 文件.目录和路径 在开 ...
- C# 基础知识系列- 15 异常处理篇
0. 前言 为什么我们需要异常处理?什么是异常? 在汉语中,异常指非正常的:不同于平常的.翻译到程序中,就是指会导致程序无法按照既定逻辑运行的意外,或者说是错误.可能会有小伙伴好奇了,我们的程序不是正 ...
- C# 基础知识系列- 16 开发工具篇
0. 前言 这是C# 基础知识系列的最后一个内容讲解篇,下一篇是基础知识-实战篇.这一篇主要讲解一下C#程序的结构和主要编程工具. 1. 工具 工欲善其事必先利其器,在实际动手之前我们先来看看想要编写 ...
- C# 基础知识系列- 3 集合数组
简单的介绍一下集合,通俗来讲就是用来保管多个数据的方案.比如说我们是一个公司的仓库管理,公司有一堆货物需要管理,有同类的,有不同类的,总而言之就是很多.很乱.我们对照集合的概念对仓库进行管理的话,那么 ...
- C# 基础知识系列- 10 反射和泛型(二)
0. 前言 这篇文章延续<C# 基础知识系列- 5 反射和泛型>,继续介绍C#在反射所开发的功能和做的努力.上一篇文章大概介绍了一下泛型和反射的一些基本内容,主要是通过获取对象的类型,然后 ...
随机推荐
- canvas 实现光线沿不规则路径运动
canvas 实现光线沿不规则路径运动 此文章为原创,请勿转载 1.svg实现 2.canvas实现 3.坑点 svg让动画沿着不规则路径运动 查阅svg文档后发现,svg动画运动有两种实现方式,且都 ...
- GPS定位模块返回数据的处理
本项目采用的是微科的VK2828U7G5LF,根据NMEA0183协议,打算采用反馈GPGLL语句来进行数据的处理. 1. 首先,本GPS模块默认的波特率是9600,因此,我们仅需要设置打开GPGLL ...
- Python 中如何查看进行反汇编
dis模块 Python 反汇编是通过 dis 这个模块来查看的,一般有两种方式可以用来查看 方式一: 在命令行中使用 dis 查看 >>> def test ...
- 【Java】【常用类】Object 基类 源码学习
源码总览: 有好些都是native本地方法,背后是C++写的 没有关于构造器的描述,默认编译器提供的无参构造 https://blog.csdn.net/dmw412724/article/detai ...
- sqlserver2008 服务器实例连接
一.sqlserver 配置管理器里面,看sqlserver服务那个,如果只有一个mssqlserver,那就用local或者.来访问,如果不是,可能有命名实例.
- python 自动打包,发送邮件(包括附件)至多个收件人(qq邮箱,163邮箱)
-----------------------------打包部分---------------------------------- import zipfile def zipDir(dirpat ...
- Cobalt Strike系列教程第六章:安装扩展
Cobalt Strike系列教程分享如约而至,新关注的小伙伴可以先回顾一下前面的内容: Cobalt Strike系列教程第一章:简介与安装 Cobalt Strike系列教程第二章:Beacon详 ...
- A - Wireless Network POJ - 2236
题目大意:有n台坏掉的电脑,给出每台电脑的坐标,然后每次询问输入0(字符) x,表示电脑x恢复正常,输入S x y 询问x和y是否可以联网.只要是x和y的距离小于距离d,那么就可以联网,如果有个中介c ...
- B - How Many Equations Can You Find dfs
Now give you an string which only contains 0, 1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9.You are asked to add the sig ...
- ubuntu16.04-交叉编译-SeetaFaceEngine-master
0.前言 在要移植opecv和SeetaFaceEngine-master到ARM板子上运行的所有步骤之前,有几点需要注意的: 查看板子运行的Kernel版本 交叉编译工具链的gcc版本,关键就是工具 ...