搜索所有连接的驱动器的最佳和有效方法是什么

本文关键字:有效 方法 是什么 最佳 驱动器 连接 搜索 | 更新日期: 2023-09-27 18:35:28

我需要在所有连接的驱动器(逻辑和物理驱动器)中搜索特定的文件类型(例如.mp4)。我知道我可以编写一个递归函数来做到这一点。但我正在寻找一种最有效的方法,因为这可能是一个耗时和 CPU 消耗的操作。

搜索所有连接的驱动器的最佳和有效方法是什么

最后我让它工作了。代码如下:

 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;
        }
    }

你可以利用 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");

由于此操作可能需要一些时间,因此可以使用后台工作线程在后台线程中运行它。

此外,由于输出可能非常大,您可以考虑输出到文件(例如,通过在 /s/b 后添加> out.txt)并处理文件,而不是返回字符串数组。

编辑:
您可以通过并行搜索驱动器来提高性能。

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;
}