C# 基础知识系列- 17 小工具优化

C# 基础知识系列- 17 小工具优化

  1. 前语
    不知道有没有着手能力强的小伙伴照着上一篇的内容写进程序呢?如果有的话,应该会在运用的时分发现以下几个问题:

每次发动都需求通过绵长的时刻去遍历磁盘里的文件目录
由于数据是用的字典保存的,所以会耗费许多的内存空间
不能屡次查询
现在咱们就针对这些问题,让咱们的小工具有用起来。

  1. 剖析与完结
    在着手之前,咱们先剖析一下问题。在实践开发之前,无论是接到什么需求都要先仔细剖析一下,确定好计划再着手方为开发的正路。嗯,没缺点。由于开发进程中跟产品对线、跟客户对线要占整个项目的一半左右时刻。好了,不废话了。持续:

遍历文件目录的时刻过长,那么咱们是不是能够用异步并发去遍历呢?

数据用字典保存会耗费内存空间,那么咱们是不是能够用其他的办法保存呢?

不能屡次查询,是不是能够运用循环,然后设置一个退出条件?

1.1 C#的异步/并发完结
在C#里,异步和并发的完结是依据线程、使命来完结的。在之前《C# 基础知识系列- 12 使命和多线程》里大约介绍了一下线程和使命,咱们知道线程自身是无法回来数据的,它与主线程进行数据交互的进程非常需求留意线程安全。而使命能够回来数据,不需求像线程相同小心谨慎地与主线程进行数据交互。使命有一个长处,它比线程更轻量,所以在当时环境下咱们能够试试使命。

当然,线程也有长处,那就是线程的运转环境相对更关闭一点,它能完结一个长的大型运算。

那么持续上一篇的内容,先引证 :

using System.Threading.Tasks;
先提取一组依据可枚举目录调集创立使命组并获得成果的办法:

public static Dictionary> OverDirectories(IEnumerable directories)
{

var tasks = directories.Select(dir => Task.Run(()=>OverDirectories(dir))).ToArray();
Task.WaitAll(tasks);// 这行的意思是等候一切使命完结
return Concat(tasks.Select(t=>t.Result).ToArray());

}
然后改造原有的OverDirectories办法:

public static Dictionary> OverDirectories(DirectoryInfo rootDirectory)
{

Console.WriteLine($"正在遍历目录:{rootDirectory.FullName}");
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 dirs = rootDirectory.EnumerateDirectories();
return Concat(dict, OverDirectories(dirs));// 选用线程版的办法进行遍历
}
catch (System.Exception e)
{
Console.WriteLine($"过错信息:{e}");//打印过错信息
}
return dict;

}
1.2 数据复用
抱负状态下,咱们的数据应该是保存在数据库的,但由于数据库的操作是鄙人一系列的教程中,所以现在只能放弃这个想象。

那么,运用现有办法,咱们能够运用文件作为缓存的办法,也就是说把数据保存在文件里,在需求的时分从文件中读取出来。这时分就需求一组操作文件的办法。

首要,声明一个静态变量:

public static readonly string TempFile = "temp.txt";
然后编写读取、寄存数据的办法:

public static void WriteLinesToTemp(List lines)
{

File.AppendAllLines(TempFile, lines);

}

public static List Search(string file)
{

var lines = File.ReadLines(file);
var results = lines.Where(line=>Path.GetFileNameWithoutExtension(line).Contains(file));
return results.ToList();

}
这时分在文件中寄存的都是途径文件,所以需求从头修正遍历文件途径的办法,只保存途径:

public static List OverDirectories(DirectoryInfo rootDirectory)
{

Console.WriteLine($"正在遍历目录:{rootDirectory.FullName}");
List<string> files = new List<string>();
try
{
files.AddRange(rootDirectory.GetFiles().Select(f=>f.FullName).ToList());
Console.WriteLine($"在目录:{rootDirectory.FullName} 下 找到 文件:{files.Count} 个");
}
catch(Exception e)
{
Console.WriteLine($"加载目录:{rootDirectory.FullName} 中t过错信息:{e}");//打印过错信息
}
try
{
var dirs = rootDirectory.GetDirectories();
OverDirectories(dirs);
}
catch (System.Exception e)
{
Console.WriteLine($"鄙人探目录{rootDirectory.FullName}时发作过错:{e}");
}
return files;

}

public static void OverDirectories(IEnumerable directories)
{

var tasks =new List<Task<List<string>>>( directories.Select(dir => Task.Run(()=>OverDirectories(dir))));
while(tasks.Any())
{
var completeds = tasks.Where(t=>t.IsCompleted).ToList(); // 提取一切已完结的使命
foreach(var t in completeds)
{
WriteLinesToTemp(t.Result);// 保存文件列
tasks.Remove(t);//移除已处理的使命
}
}

}
最终修正主办法,设置发动时遍历途径的规矩:

static void Main(string[] args)
{

if(!File.Exists(TempFile))// 缓存文件存在,则以为前次现已遍历成功了
{
var drivers = GetDrivers();
OverDirectories(drivers);
}
Console.WriteLine("请输入要查询的文件名:");
var search = Console.ReadLine().Trim();

}
1.3 循环运用并设置退出条件
设置用户输入q或Q的时分退出程序,这时分就需求改造Main办法了:

static void Main(string[] args)
{

Console.WriteLine("文件查询小工具发动了……");
if(!File.Exists(TempFile))
{
Console.WriteLine("没有加载缓存记载,数据加载中……");
var drivers = GetDrivers();
OverDirectories(drivers);
Console.WriteLine("数据加载完结");
Thread.Sleep(500);
Console.Clear();// 铲除控制台
}
while(true)
{
Console.WriteLine("请输入要查询的文件名(输入q/Q 退出):");
var search = Console.ReadLine().Trim();// 去除剩余的空白字符
if(search == "q" || search == "Q")//增加退出条件
{
break;
}
Console.WriteLine("查询中……");
var results = Search(search);
Console.WriteLine("查询成果:");
foreach(var r in results)
{
Console.WriteLine(r);
}
}
Console.WriteLine("程序已退出!");

}
在main 办法里加了许多提示句子,以方便运用。

  1. 总结
    以上是第一次实战课的一切内容。欢迎各位小伙伴们积极评论。这个小工具并不完善,可是跟着咱们对.net core的了解和深化就会写的称心如意了。

原文地址https://www.cnblogs.com/c7jie/p/12849942.html