接続されているすべてのドライブ (論理および物理) で特定のファイル タイプ (mp4 など) を検索する必要があります。そうするために再帰関数を書くことができることを私は知っています。しかし、これは時間と CPU を消費する操作になる可能性があるため、最も効率的な方法を探しています。
質問する
207 次
2 に答える
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 に答える
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 に答える