高性能的 C# 文件搜索工具,使用多线程和异步 IO 技术实现快速磁盘文件搜索,支持通配符匹配、大小过滤、日期过滤等高级功能。
代码
1. 主窗体代码 (MainForm.cs)
csharp
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing;
namespace FastFileSearch
{
public partial class MainForm : Form
{
private readonly ConcurrentBag<string> searchResults = new ConcurrentBag<string>();
private CancellationTokenSource cancellationTokenSource;
private readonly Stopwatch searchStopwatch = new Stopwatch();
private int filesScanned;
private long totalBytesScanned;
public MainForm()
{
InitializeComponent();
InitializeUI();
LoadRecentSearches();
}
private void InitializeUI()
{
// 窗体设置
this.Text = "闪电文件搜索工具";
this.Size = new Size(900, 650);
this.StartPosition = FormStartPosition.CenterScreen;
this.BackColor = Color.FromArgb(240, 243, 249);
this.Font = new Font("Segoe UI", 9);
// 创建控件
int yPos = 20;
int labelWidth = 120;
int controlWidth = 300;
int rowHeight = 35;
// 搜索路径
lblPath = new Label { Text = "搜索路径:", Location = new Point(20, yPos), Size = new Size(labelWidth, 20), TextAlign = ContentAlignment.MiddleRight };
txtPath = new TextBox { Location = new Point(150, yPos), Size = new Size(controlWidth, 25), Text = @"C:\" };
btnBrowse = new Button { Text = "浏览...", Location = new Point(460, yPos), Size = new Size(75, 25), BackColor = Color.SteelBlue, ForeColor = Color.White, FlatStyle = FlatStyle.Flat };
btnBrowse.FlatAppearance.BorderSize = 0;
btnBrowse.Click += BtnBrowse_Click;
// 文件名模式
yPos += rowHeight;
lblPattern = new Label { Text = "文件名模式:", Location = new Point(20, yPos), Size = new Size(labelWidth, 20), TextAlign = ContentAlignment.MiddleRight };
txtPattern = new TextBox { Location = new Point(150, yPos), Size = new Size(controlWidth, 25), Text = "*.txt" };
// 文件大小过滤
yPos += rowHeight;
lblSize = new Label { Text = "文件大小:", Location = new Point(20, yPos), Size = new Size(labelWidth, 20), TextAlign = ContentAlignment.MiddleRight };
cmbSizeOperator = new ComboBox { Location = new Point(150, yPos), Size = new Size(80, 25), DropDownStyle = ComboBoxStyle.DropDownList };
cmbSizeOperator.Items.AddRange(new object[] { "大于", "小于", "等于", "介于" });
cmbSizeOperator.SelectedIndex = 0;
txtSize1 = new TextBox { Location = new Point(240, yPos), Size = new Size(80, 25), Text = "1" };
lblSizeUnit = new Label { Text = "MB", Location = new Point(325, yPos), Size = new Size(30, 20), TextAlign = ContentAlignment.MiddleLeft };
lblSizeTo = new Label { Text = "到", Location = new Point(360, yPos), Size = new Size(20, 20), TextAlign = ContentAlignment.MiddleCenter, Visible = false };
txtSize2 = new TextBox { Location = new Point(380, yPos), Size = new Size(80, 25), Visible = false };
cmbSizeOperator.SelectedIndexChanged += (s, e) => {
bool between = cmbSizeOperator.SelectedIndex == 3;
lblSizeTo.Visible = between;
txtSize2.Visible = between;
};
// 修改时间过滤
yPos += rowHeight;
lblDate = new Label { Text = "修改时间:", Location = new Point(20, yPos), Size = new Size(labelWidth, 20), TextAlign = ContentAlignment.MiddleRight };
cmbDateOperator = new ComboBox { Location = new Point(150, yPos), Size = new Size(80, 25), DropDownStyle = ComboBoxStyle.DropDownList };
cmbDateOperator.Items.AddRange(new object[] { "今天", "昨天", "本周", "上周", "本月", "上月", "今年", "去年", "自定义" });
cmbDateOperator.SelectedIndex = 0;
dtpDate1 = new DateTimePicker { Location = new Point(240, yPos), Size = new Size(150, 25), Format = DateTimePickerFormat.Short, Visible = false };
lblDateTo = new Label { Text = "到", Location = new Point(395, yPos), Size = new Size(20, 20), TextAlign = ContentAlignment.MiddleCenter, Visible = false };
dtpDate2 = new DateTimePicker { Location = new Point(420, yPos), Size = new Size(150, 25), Format = DateTimePickerFormat.Short, Visible = false };
cmbDateOperator.SelectedIndexChanged += (s, e) => {
bool custom = cmbDateOperator.SelectedIndex == 8;
dtpDate1.Visible = custom;
lblDateTo.Visible = custom;
dtpDate2.Visible = custom;
};
// 搜索按钮
yPos += rowHeight + 10;
btnSearch = new Button { Text = "开始搜索", Location = new Point(150, yPos), Size = new Size(100, 35), BackColor = Color.ForestGreen, ForeColor = Color.White, FlatStyle = FlatStyle.Flat, Font = new Font("Segoe UI", 10, FontStyle.Bold) };
btnSearch.FlatAppearance.BorderSize = 0;
btnSearch.Click += BtnSearch_Click;
btnStop = new Button { Text = "停止搜索", Location = new Point(260, yPos), Size = new Size(100, 35), BackColor = Color.IndianRed, ForeColor = Color.White, FlatStyle = FlatStyle.Flat, Font = new Font("Segoe UI", 10, FontStyle.Bold), Enabled = false };
btnStop.FlatAppearance.BorderSize = 0;
btnStop.Click += BtnStop_Click;
// 结果列表
yPos += rowHeight + 20;
lstResults = new ListView { Location = new Point(20, yPos), Size = new Size(840, 300), View = View.Details, FullRowSelect = true, GridLines = true };
lstResults.Columns.Add("文件名", 200);
lstResults.Columns.Add("路径", 400);
lstResults.Columns.Add("大小", 100);
lstResults.Columns.Add("修改日期", 140);
lstResults.SmallImageList = new ImageList();
lstResults.SmallImageList.Images.Add(SystemIcons.File.ToBitmap());
// 状态栏
statusStrip = new StatusStrip();
toolStripStatusLabel = new ToolStripStatusLabel();
toolStripProgressBar = new ToolStripProgressBar();
statusStrip.Items.Add(toolStripStatusLabel);
statusStrip.Items.Add(toolStripProgressBar);
statusStrip.Location = new Point(0, this.ClientSize.Height - 22);
statusStrip.Size = new Size(this.ClientSize.Width, 22);
statusStrip.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
// 添加控件到窗体
this.Controls.AddRange(new Control[] {
lblPath, txtPath, btnBrowse,
lblPattern, txtPattern,
lblSize, cmbSizeOperator, txtSize1, lblSizeUnit, lblSizeTo, txtSize2,
lblDate, cmbDateOperator, dtpDate1, lblDateTo, dtpDate2,
btnSearch, btnStop,
lstResults, statusStrip
});
// 添加右键菜单
var contextMenu = new ContextMenuStrip();
var openFolderItem = new ToolStripMenuItem("打开所在文件夹");
openFolderItem.Click += (s, e) => OpenContainingFolder();
var copyPathItem = new ToolStripMenuItem("复制文件路径");
copyPathItem.Click += (s, e) => CopyFilePath();
contextMenu.Items.Add(openFolderItem);
contextMenu.Items.Add(copyPathItem);
lstResults.ContextMenuStrip = contextMenu;
}
#region 控件声明
private Label lblPath, lblPattern, lblSize, lblDate;
private TextBox txtPath, txtPattern, txtSize1, txtSize2;
private ComboBox cmbSizeOperator, cmbDateOperator;
private Button btnBrowse, btnSearch, btnStop;
private Label lblSizeUnit, lblSizeTo, lblDateTo;
private DateTimePicker dtpDate1, dtpDate2;
private ListView lstResults;
private StatusStrip statusStrip;
private ToolStripStatusLabel toolStripStatusLabel;
private ToolStripProgressBar toolStripProgressBar;
#endregion
#region 事件处理
private void BtnBrowse_Click(object sender, EventArgs e)
{
using (FolderBrowserDialog folderDialog = new FolderBrowserDialog())
{
folderDialog.Description = "选择搜索目录";
folderDialog.RootFolder = Environment.SpecialFolder.MyComputer;
folderDialog.ShowNewFolderButton = false;
if (folderDialog.ShowDialog() == DialogResult.OK)
{
txtPath.Text = folderDialog.SelectedPath;
}
}
}
private async void BtnSearch_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(txtPath.Text) || !Directory.Exists(txtPath.Text))
{
MessageBox.Show("请选择有效的搜索路径", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if (string.IsNullOrWhiteSpace(txtPattern.Text))
{
MessageBox.Show("请输入文件名模式", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
// 准备UI
btnSearch.Enabled = false;
btnStop.Enabled = true;
lstResults.Items.Clear();
searchResults.Clear();
filesScanned = 0;
totalBytesScanned = 0;
searchStopwatch.Restart();
toolStripProgressBar.Value = 0;
toolStripProgressBar.Maximum = 100;
toolStripStatusLabel.Text = "搜索中...";
// 创建取消令牌
cancellationTokenSource = new CancellationTokenSource();
CancellationToken token = cancellationTokenSource.Token;
try
{
// 获取搜索参数
string path = txtPath.Text;
string pattern = txtPattern.Text;
long sizeLimit = ParseSizeFilter();
DateTime? dateFrom = ParseDateFilter(out DateTime? dateTo);
// 执行搜索
await Task.Run(() => SearchFiles(path, pattern, sizeLimit, dateFrom, dateTo, token), token);
// 显示结果
DisplayResults();
}
catch (OperationCanceledException)
{
toolStripStatusLabel.Text = "搜索已取消";
}
catch (Exception ex)
{
MessageBox.Show($"搜索过程中发生错误: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
toolStripStatusLabel.Text = "搜索失败";
}
finally
{
// 恢复UI
btnSearch.Enabled = true;
btnStop.Enabled = false;
searchStopwatch.Stop();
toolStripStatusLabel.Text = $"搜索完成! 共找到 {lstResults.Items.Count} 个文件, 耗时 {searchStopwatch.Elapsed.TotalSeconds:0.00} 秒";
}
}
private void BtnStop_Click(object sender, EventArgs e)
{
cancellationTokenSource?.Cancel();
btnStop.Enabled = false;
toolStripStatusLabel.Text = "正在停止搜索...";
}
private void OpenContainingFolder()
{
if (lstResults.SelectedItems.Count == 0) return;
string filePath = lstResults.SelectedItems[0].SubItems[1].Text;
string folderPath = Path.GetDirectoryName(filePath);
if (Directory.Exists(folderPath))
{
Process.Start("explorer.exe", $"/select,\"{filePath}\"");
}
}
private void CopyFilePath()
{
if (lstResults.SelectedItems.Count == 0) return;
string filePath = lstResults.SelectedItems[0].SubItems[1].Text;
Clipboard.SetText(filePath);
}
#endregion
#region 搜索功能实现
private long ParseSizeFilter()
{
if (!long.TryParse(txtSize1.Text, out long size)) return 0;
// 转换为字节
switch (lblSizeUnit.Text)
{
case "KB": return size * 1024;
case "MB": return size * 1024 * 1024;
case "GB": return size * 1024 * 1024 * 1024;
default: return size; // 默认是字节
}
}
private DateTime? ParseDateFilter(out DateTime? dateTo)
{
dateTo = null;
int index = cmbDateOperator.SelectedIndex;
if (index < 8) // 非自定义
{
DateTime now = DateTime.Now;
switch (index)
{
case 0: // 今天
return now.Date;
case 1: // 昨天
return now.AddDays(-1).Date;
case 2: // 本周
return now.AddDays(-(int)now.DayOfWeek).Date;
case 3: // 上周
return now.AddDays(-(int)now.DayOfWeek - 7).Date;
case 4: // 本月
return new DateTime(now.Year, now.Month, 1);
case 5: // 上月
return new DateTime(now.Year, now.Month, 1).AddMonths(-1);
case 6: // 今年
return new DateTime(now.Year, 1, 1);
case 7: // 去年
return new DateTime(now.Year - 1, 1, 1);
}
}
else // 自定义
{
dateTo = dtpDate2.Value;
return dtpDate1.Value;
}
return null;
}
private void SearchFiles(string rootPath, string pattern, long sizeLimit, DateTime? dateFrom, DateTime? dateTo, CancellationToken token)
{
// 使用并行处理加速搜索
var options = new ParallelOptions
{
CancellationToken = token,
MaxDegreeOfParallelism = Environment.ProcessorCount
};
// 使用栈代替递归遍历目录
var directories = new ConcurrentStack<string>();
directories.Push(rootPath);
// 使用任务并行库处理目录
var tasks = new List<Task>();
int taskCount = Math.Min(Environment.ProcessorCount * 2, 16); // 限制最大任务数
for (int i = 0; i < taskCount; i++)
{
tasks.Add(Task.Run(() =>
{
while (!token.IsCancellationRequested && directories.TryPop(out string currentDir))
{
try
{
// 处理当前目录中的文件
ProcessDirectory(currentDir, pattern, sizeLimit, dateFrom, dateTo, token);
// 获取子目录
var subDirs = Directory.EnumerateDirectories(currentDir);
foreach (var dir in subDirs)
{
if (!token.IsCancellationRequested)
{
directories.Push(dir);
}
}
}
catch (UnauthorizedAccessException)
{
// 忽略无权限访问的目录
}
catch (PathTooLongException)
{
// 忽略路径过长的目录
}
catch (Exception ex)
{
Debug.WriteLine($"处理目录时出错: {ex.Message}");
}
}
}, token));
}
// 等待所有任务完成
Task.WaitAll(tasks.ToArray(), token);
}
private void ProcessDirectory(string directory, string pattern, long sizeLimit, DateTime? dateFrom, DateTime? dateTo, CancellationToken token)
{
try
{
// 处理文件
var files = Directory.EnumerateFiles(directory, pattern, SearchOption.TopDirectoryOnly);
foreach (var file in files)
{
if (token.IsCancellationRequested) return;
try
{
FileInfo fileInfo = new FileInfo(file);
bool sizeMatch = CheckSize(fileInfo.Length, sizeLimit);
bool dateMatch = CheckDate(fileInfo.LastWriteTime, dateFrom, dateTo);
if (sizeMatch && dateMatch)
{
searchResults.Add(file);
}
// 更新进度
Interlocked.Increment(ref filesScanned);
Interlocked.Add(ref totalBytesScanned, fileInfo.Length);
UpdateProgress();
}
catch (UnauthorizedAccessException)
{
// 忽略无权限访问的文件
}
catch (PathTooLongException)
{
// 忽略路径过长的文件
}
}
}
catch (UnauthorizedAccessException)
{
// 忽略无权限访问的目录
}
catch (PathTooLongException)
{
// 忽略路径过长的目录
}
}
private bool CheckSize(long fileSize, long limit)
{
int operatorIndex = cmbSizeOperator.SelectedIndex;
switch (operatorIndex)
{
case 0: // 大于
return fileSize > limit;
case 1: // 小于
return fileSize < limit;
case 2: // 等于
return fileSize == limit;
case 3: // 介于
if (long.TryParse(txtSize2.Text, out long size2))
{
long limit2 = ParseSizeFilter(txtSize2.Text, lblSizeUnit.Text);
return fileSize >= Math.Min(limit, limit2) && fileSize <= Math.Max(limit, limit2);
}
return fileSize >= limit;
default:
return true;
}
}
private long ParseSizeFilter(string sizeText, string unit)
{
if (!long.TryParse(sizeText, out long size)) return 0;
switch (unit)
{
case "KB": return size * 1024;
case "MB": return size * 1024 * 1024;
case "GB": return size * 1024 * 1024 * 1024;
default: return size;
}
}
private bool CheckDate(DateTime fileDate, DateTime? dateFrom, DateTime? dateTo)
{
if (!dateFrom.HasValue) return true;
if (dateTo.HasValue)
{
return fileDate >= dateFrom.Value && fileDate <= dateTo.Value;
}
else
{
// 单日期比较(当天)
return fileDate.Date == dateFrom.Value.Date;
}
}
private void UpdateProgress()
{
if (filesScanned % 100 == 0) // 每100个文件更新一次UI
{
int progressPercent = (int)(totalBytesScanned / (1024.0 * 1024 * 1024) * 10); // 粗略估算
progressPercent = Math.Min(progressPercent, 100);
this.Invoke((MethodInvoker)delegate {
toolStripProgressBar.Value = progressPercent;
toolStripStatusLabel.Text = $"搜索中... 已扫描 {filesScanned} 个文件, {totalBytesScanned / (1024 * 1024)} MB";
});
}
}
private void DisplayResults()
{
this.Invoke((MethodInvoker)delegate {
foreach (var file in searchResults)
{
try
{
FileInfo fileInfo = new FileInfo(file);
ListViewItem item = new ListViewItem(fileInfo.Name);
item.SubItems.Add(fileInfo.DirectoryName);
item.SubItems.Add(FormatFileSize(fileInfo.Length));
item.SubItems.Add(fileInfo.LastWriteTime.ToString("yyyy-MM-dd HH:mm"));
item.ImageIndex = 0;
lstResults.Items.Add(item);
}
catch
{
// 忽略无法访问的文件
}
}
});
}
private string FormatFileSize(long bytes)
{
string[] sizes = { "B", "KB", "MB", "GB", "TB" };
int order = 0;
double len = bytes;
while (len >= 1024 && order < sizes.Length - 1)
{
order++;
len /= 1024;
}
return $"{len:0.##} {sizes[order]}";
}
#endregion
#region 辅助功能
private void LoadRecentSearches()
{
// 在实际应用中,这里可以从配置文件加载最近的搜索路径
}
private void SaveRecentSearches()
{
// 在实际应用中,这里可以将最近的搜索路径保存到配置文件
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
cancellationTokenSource?.Cancel();
base.OnFormClosing(e);
}
#endregion
}
}
2. 程序入口 (Program.cs)
csharp
using System;
using System.Windows.Forms;
namespace FastFileSearch
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
}
3. 应用程序配置文件 (App.config)
xml
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/>
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
功能特点
1. 高性能搜索
- 多线程并行搜索:使用任务并行库(TPL)和多线程技术
- 异步文件枚举:避免阻塞UI线程
- 栈式目录遍历:避免递归导致的堆栈溢出
- 批量UI更新:减少界面刷新次数
2. 高级过滤功能
- 文件名模式:支持通配符(*, ?)
- 文件大小过滤:大于、小于、等于、介于
- 日期过滤:今天、昨天、本周、上周、本月、上月、今年、去年、自定义范围
- 组合过滤:同时使用多种过滤条件
3. 用户友好界面
- 直观的参数设置:分组布局,清晰的标签
- 实时进度显示:进度条和状态信息
- 详细结果列表:文件名、路径、大小、修改日期
- 右键菜单:打开所在文件夹、复制文件路径
- 响应式设计:适应不同屏幕尺寸
4. 健壮性设计
- 异常处理:捕获并处理常见文件系统异常
- 取消支持:随时停止长时间运行的搜索
- 资源清理:正确释放文件句柄和系统资源
- 权限处理:优雅地处理无权限访问的目录
技术亮点
1. 并行搜索算法
csharp
// 使用并行处理加速搜索
var options = new ParallelOptions
{
CancellationToken = token,
MaxDegreeOfParallelism = Environment.ProcessorCount
};
// 使用栈代替递归遍历目录
var directories = new ConcurrentStack<string>();
directories.Push(rootPath);
// 创建多个任务处理目录
for (int i = 0; i < taskCount; i++)
{
tasks.Add(Task.Run(() =>
{
while (!token.IsCancellationRequested && directories.TryPop(out string currentDir))
{
// 处理目录...
}
}, token));
}
2. 高效文件处理
csharp
// 批量处理文件
var files = Directory.EnumerateFiles(directory, pattern, SearchOption.TopDirectoryOnly);
foreach (var file in files)
{
if (token.IsCancellationRequested) return;
FileInfo fileInfo = new FileInfo(file);
bool sizeMatch = CheckSize(fileInfo.Length, sizeLimit);
bool dateMatch = CheckDate(fileInfo.LastWriteTime, dateFrom, dateTo);
if (sizeMatch && dateMatch)
{
searchResults.Add(file);
}
// 更新进度
Interlocked.Increment(ref filesScanned);
Interlocked.Add(ref totalBytesScanned, fileInfo.Length);
UpdateProgress();
}
3. 智能过滤系统
csharp
// 文件大小过滤
private bool CheckSize(long fileSize, long limit)
{
int operatorIndex = cmbSizeOperator.SelectedIndex;
switch (operatorIndex)
{
case 0: return fileSize > limit; // 大于
case 1: return fileSize < limit; // 小于
case 2: return fileSize == limit; // 等于
case 3: // 介于
if (long.TryParse(txtSize2.Text, out long size2))
{
long limit2 = ParseSizeFilter(txtSize2.Text, lblSizeUnit.Text);
return fileSize >= Math.Min(limit, limit2) &&
fileSize <= Math.Max(limit, limit2);
}
return fileSize >= limit;
default: return true;
}
}
// 日期过滤
private bool CheckDate(DateTime fileDate, DateTime? dateFrom, DateTime? dateTo)
{
if (!dateFrom.HasValue) return true;
if (dateTo.HasValue)
{
return fileDate >= dateFrom.Value && fileDate <= dateTo.Value;
}
else
{
return fileDate.Date == dateFrom.Value.Date;
}
}
4. 进度反馈机制
csharp
// 更新进度
private void UpdateProgress()
{
if (filesScanned % 100 == 0) // 每100个文件更新一次UI
{
int progressPercent = (int)(totalBytesScanned / (1024.0 * 1024 * 1024) * 10);
progressPercent = Math.Min(progressPercent, 100);
this.Invoke((MethodInvoker)delegate {
toolStripProgressBar.Value = progressPercent;
toolStripStatusLabel.Text = $"搜索中... 已扫描 {filesScanned} 个文件, {totalBytesScanned / (1024 * 1024)} MB";
});
}
}
使用说明
1. 基本搜索
- 在"搜索路径"中选择或输入要搜索的目录
- 在"文件名模式"中输入文件名模式(如 *.txt)
- 点击"开始搜索"按钮
2. 高级过滤
- 文件大小:选择操作符并输入大小值
- 修改时间:选择预设范围或自定义日期范围
- 组合使用:同时使用多个过滤条件缩小搜索范围
3. 结果操作
- 查看详情:在结果列表中查看文件详细信息
- 打开文件夹:右键点击文件选择"打开所在文件夹"
- 复制路径:右键点击文件选择"复制文件路径"
4. 性能优化建议
- 避免在全盘搜索时使用过于宽泛的模式(如 .)
- 对于大型目录,使用更具体的路径
- 合理设置文件大小过滤条件
- 使用日期过滤减少搜索范围
参考代码 C# 快速搜索磁盘文件 www.youwenfan.com/contentcst/39200.html
扩展功能建议
1. 添加文件内容搜索
csharp
private bool ContainsText(string filePath, string searchText)
{
try
{
using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var reader = new StreamReader(stream, Encoding.UTF8, true))
{
string line;
while ((line = reader.ReadLine()) != null)
{
if (line.Contains(searchText))
return true;
}
}
}
catch
{
// 忽略无法读取的文件
}
return false;
}
2. 添加文件预览功能
csharp
private void ShowFilePreview(string filePath)
{
var previewForm = new Form
{
Text = $"预览: {Path.GetFileName(filePath)}",
Size = new Size(600, 400)
};
var textBox = new TextBox
{
Multiline = true,
ScrollBars = ScrollBars.Both,
Dock = DockStyle.Fill,
ReadOnly = true
};
try
{
textBox.Text = File.ReadAllText(filePath);
}
catch
{
textBox.Text = "无法预览此文件类型";
}
previewForm.Controls.Add(textBox);
previewForm.ShowDialog();
}
3. 添加搜索历史记录
csharp
private List<SearchHistoryItem> searchHistory = new List<SearchHistoryItem>();
private void SaveSearchToHistory()
{
var historyItem = new SearchHistoryItem
{
Path = txtPath.Text,
Pattern = txtPattern.Text,
SizeOperator = cmbSizeOperator.SelectedIndex,
SizeValue = txtSize1.Text,
DateOperator = cmbDateOperator.SelectedIndex,
DateValue = dtpDate1.Value
};
searchHistory.Add(historyItem);
if (searchHistory.Count > 10) searchHistory.RemoveAt(0);
// 保存到配置文件
SaveHistoryToFile();
}
private void LoadHistoryFromFile()
{
// 从配置文件加载历史记录
}
4. 添加文件类型图标
csharp
// 初始化图标列表
private void InitializeIconList()
{
lstResults.SmallImageList = new ImageList();
lstResults.LargeImageList = new ImageList();
// 添加常见文件类型图标
AddFileIcon(".txt", SystemIcons.Document);
AddFileIcon(".doc", OfficeIcons.Word);
AddFileIcon(".xls", OfficeIcons.Excel);
AddFileIcon(".pdf", SystemIcons.WinLogo);
// 添加更多文件类型...
}
private void AddFileIcon(string extension, Icon icon)
{
lstResults.SmallImageList.Images.Add(extension, icon);
lstResults.LargeImageList.Images.Add(extension, icon);
}
// 在显示结果时使用图标
private void DisplayResults()
{
foreach (var file in searchResults)
{
string ext = Path.GetExtension(file).ToLower();
ListViewItem item = new ListViewItem(Path.GetFileName(file));
item.ImageKey = lstResults.SmallImageList.Images.ContainsKey(ext) ? ext : "default";
// 添加其他列...
lstResults.Items.Add(item);
}
}
性能优化技巧
-
目录遍历优化:
- 跳过系统目录(如 System Volume Information)
- 忽略隐藏文件和目录
- 使用原生API(如 P/Invoke)加速文件枚举
-
内存管理:
- 使用流式处理避免大文件加载到内存
- 定期清理不再使用的对象
- 限制结果集大小防止内存溢出
-
磁盘访问优化:
- 按磁盘簇大小读取文件
- 避免频繁的磁盘寻道操作
- 使用异步IO减少等待时间
-
并行处理优化:
- 根据磁盘性能调整并行度
- 使用任务窃取(task stealing)平衡负载
- 避免过度并行导致磁盘争用
常见问题解决
1. 搜索速度慢
- 原因:全盘搜索或大目录搜索
- 解决 :
- 使用更具体的搜索路径
- 添加文件大小和日期过滤
- 避免在网络驱动器上搜索
2. 内存占用过高
- 原因:结果集过大
- 解决 :
- 添加结果数量限制
- 使用分页显示结果
- 定期清理已完成任务的资源
3. 权限错误
- 原因:访问受保护目录
- 解决 :
- 以管理员身份运行程序
- 跳过无权限访问的目录
- 记录无法访问的路径供用户参考
4. 文件类型识别错误
- 原因:文件扩展名与实际类型不符
- 解决 :
- 使用文件签名(magic number)检测真实类型
- 提供手动选择文件类型的选项
- 允许用户添加自定义文件类型规则
项目总结
这个 C# 文件搜索工具提供了高性能的磁盘文件搜索功能,具有以下特点:
-
极速搜索:
- 多线程并行处理
- 异步文件枚举
- 智能目录遍历
-
强大过滤:
- 文件名模式匹配
- 文件大小过滤
- 修改日期过滤
- 组合条件搜索
-
用户友好:
- 直观的参数设置
- 实时进度反馈
- 详细结果展示
- 便捷的结果操作
-
健壮稳定:
- 全面的异常处理
- 资源高效管理
- 支持长时间运行
- 可随时取消