我需要在所有连接的驱动器(逻辑驱动器和物理驱动器)中搜索特定文件类型(例如 mp4)。我知道我可以编写一个递归函数来做到这一点。但我正在寻找一种最有效的方法,因为这可能是一个耗时且消耗 CPU 的操作。
问问题
207 次
2 回答
0
你可以利用这个dir
命令,让文件系统做它擅长的事情。
static string[] SearchFiles(params string[] patterns)
{
var searchPatterns = DriveInfo.GetDrives()
.Where(d => d.IsReady && d.DriveType != DriveType.NoRootDirectory)
.SelectMany(d => patterns.Select(p => d.RootDirectory + p));
using (var process = new Process())
{
process.StartInfo.FileName = Path.Combine(Environment.SystemDirectory, "cmd.exe");
process.StartInfo.Arguments = "/C dir " + String.Join(" ", searchPatterns) + " /s/b";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.CreateNoWindow = true;
process.Start();
string strOutput = process.StandardOutput.ReadToEnd();
process.WaitForExit();
return strOutput.Split(Environment.NewLine.ToArray());
}
}
并像这样使用它:
var files = SearchFiles("*.jpg", "*.mp?", "*.mpeg");
由于此操作可能需要一些时间,您可以使用BackgroundWorker在后台线程中运行它。
此外,由于输出可能非常大,您可能会考虑输出到文件(例如,通过添加> out.txt
after /s/b
)并处理文件,而不是返回字符串数组。
编辑:
您可以通过并行搜索驱动器来提高性能。
static List<string> SearchFiles(params string[] patterns)
{
var result = new List<string>();
var drives = DriveInfo.GetDrives();
Parallel.ForEach(drives, drive =>
{
if (!drive.IsReady || drive.DriveType == DriveType.NoRootDirectory)
return;
var searchPatterns = patterns.Select(p => drive.RootDirectory + p);
using (var process = new Process())
{
process.StartInfo.FileName = Path.Combine(Environment.SystemDirectory, "cmd.exe");
process.StartInfo.Arguments = "/C dir " + String.Join(" ", searchPatterns) + " /s/b";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.CreateNoWindow = true;
process.Start();
string strOutput = process.StandardOutput.ReadToEnd();
process.WaitForExit();
result.AddRange(strOutput.Split(Environment.NewLine.ToArray(), StringSplitOptions.RemoveEmptyEntries));
}
});
return result;
}
于 2012-05-26T13:12:18.440 回答
0
最后我让它工作了。代码如下:
static List<string> SearchFiles(string pattern)
{
var result = new List<string>();
foreach (string drive in Directory.GetLogicalDrives())
{
Console.WriteLine("searching " + drive);
var files = FindAccessableFiles(drive, pattern, true);
Console.WriteLine(files.Count().ToString() + " files found.");
result.AddRange(files);
}
return result;
}
private static IEnumerable<String> FindAccessableFiles(string path, string file_pattern, bool recurse)
{
Console.WriteLine(path);
var list = new List<string>();
var required_extension = "mp4";
if (File.Exists(path))
{
yield return path;
yield break;
}
if (!Directory.Exists(path))
{
yield break;
}
if (null == file_pattern)
file_pattern = "*." + required_extension;
var top_directory = new DirectoryInfo(path);
// Enumerate the files just in the top directory.
IEnumerator<FileInfo> files;
try
{
files = top_directory.EnumerateFiles(file_pattern).GetEnumerator();
}
catch (Exception ex)
{
files = null;
}
while (true)
{
FileInfo file = null;
try
{
if (files != null && files.MoveNext())
file = files.Current;
else
break;
}
catch (UnauthorizedAccessException)
{
continue;
}
catch (PathTooLongException)
{
continue;
}
yield return file.FullName;
}
if (!recurse)
yield break;
IEnumerator<DirectoryInfo> dirs;
try
{
dirs = top_directory.EnumerateDirectories("*").GetEnumerator();
}
catch (Exception ex)
{
dirs = null;
}
while (true)
{
DirectoryInfo dir = null;
try
{
if (dirs != null && dirs.MoveNext())
dir = dirs.Current;
else
break;
}
catch (UnauthorizedAccessException)
{
continue;
}
catch (PathTooLongException)
{
continue;
}
foreach (var subpath in FindAccessableFiles(dir.FullName, file_pattern, recurse))
yield return subpath;
}
}
于 2012-05-26T15:22:26.000 回答