在组织内部,经常需要在多台计算机上查找共享的文件夹和文件。本文将介绍如何开发一个用于局域网内搜索共享文件和文件夹的工具。这个工具特别适用于那些在个人系统上共享了大量文件夹的组织。
首先,要感谢Robert Deeming设计的库,他在中解释了这个库。感谢他分享了如此精彩的作品。
本文假设已经对C#有合理的理解,对线程有基本的理解,并且对局域网有一般的知识。
这个应用程序的工作原理是这样的:指定一个IP范围。工具搜索活动主机。然后,它确定每个系统共享的文件夹列表,并根据指定的关键字查找文件。
使用System.Net.NetworkingInformation
命名空间中定义的Ping
类可以实现这一点。Ping
类提供了同步和异步方法来检测远程主机是否可达。将使用异步方法,因为不想在ping远程主机时让系统暂停。以下是代码示例:
Ping pingSender = new Ping();
pingSender.PingCompleted += new PingCompletedEventHandler(AddHost);
int timeout = 1000;
byte[] buffer = new byte[] { 100 };
PingOptions options = new PingOptions(64, true);
pingSender.SendAsync("192.168.209.178", timeout, buffer, options, null);
当PingCompleted
事件被触发时,将调用PingCompletedCallback
方法。以下是如何检查Ping
操作结果的示例:
private void AddHost(object sender, PingCompletedEventArgs e)
{
PingReply reply = e.Reply;
if (reply == null) return;
if (reply.Status == IPStatus.Success)
{
// 如果远程主机被发现是活跃的,执行的代码
reply.Address returns the address.
}
}
这里就是Robert Deeming的库发挥作用的地方。这个库中定义的两个类是ShareCollection
和Share
。ShareCollection
是一个能够确定给定IP地址的共享文件夹并将信息存储在Share
类型对象中的类。以下是代码示例:
ShareCollection sc = new ShareCollection(reply.Address.ToString());
foreach (Share s in sc)
{
// 对每个Share对象执行想要的操作
s.NetName returns the name of the shared folder.
s.ShareType return the type of share.
}
要搜索特定共享中的文件,必须使用递归。基本逻辑是从共享文件夹开始。处理该文件夹中每个文件的名称。完成此操作后,递归地将相同的逻辑应用于每个子目录,直到没有文件或文件夹为止。如果目录结构太深,这种方法会出现问题。在这种情况下,工具会浪费大量时间在特定共享中查找文件。为了防止这种情况,使用搜索深度功能。搜索深度是一个整型变量,每次搜索移动到目录树中更深层次的文件夹时,该变量会增加一。当变量超过特定值(通常是一个小整数,如2或3)时,递归停止并返回。以下是代码示例:
ShareCollection sc = new ShareCollection(reply.Address.ToString());
foreach (Share share in sc)
{
RecursiveSearch(share.ToString(), 0);
}
然后声明递归函数:
private void RecursiveSearch(string path, int depth)
{
DirectoryInfo di = new DirectoryInfo(path);
if (!di.Exists) return;
depth++;
if (depth > Settings.searchDepth) return;
string keyword = Settings.keyword;
if (di.Name.ToLower().Contains(keyword.ToLower()))
{
AddRow(name, parent, "Folder");
}
foreach (FileInfo file in di.GetFiles())
{
if (file.Name.ToLower().Contains(keyword.ToLower()))
{
AddRow(file.Name, di.FullName, size);
}
}
foreach (DirectoryInfo subdir in di.GetDirectories())
{
RecursiveSearch(subdir.FullName, depth);
}
}
delegate void SetCallback(params object[] objects);
private void AddRow(params object[] objects)
{
if (this.dgvResult.InvokeRequired)
{
SetCallback d = new SetCallback(AddRow);
this.Invoke(d, new object[] { objects });
}
else
{
(dgvResult.DataSource as DataTable).Rows.Add(objects);
}
}