C#中最快的方法是在包含20000多个文件的目录中查找文件
我有一个每天晚上运行的任务,从根目录下有20000多个子文件夹的目录中提取xml文件。以下是结构的外观:C#中最快的方法是在包含20000多个文件的目录中查找文件,c#,.net,file-io,C#,.net,File Io,我有一个每天晚上运行的任务,从根目录下有20000多个子文件夹的目录中提取xml文件。以下是结构的外观: rootFolder/someFolder/someSubFolder/xml/myFile.xml rootFolder/someFolder/someSubFolder1/xml/myFile1.xml rootFolder/someFolder/someSubFolderN/xml/myFile2.xml rootFolder/someFolder1 rootFolder/someFo
rootFolder/someFolder/someSubFolder/xml/myFile.xml
rootFolder/someFolder/someSubFolder1/xml/myFile1.xml
rootFolder/someFolder/someSubFolderN/xml/myFile2.xml
rootFolder/someFolder1
rootFolder/someFolderN
因此,综上所述,结构总是相同的——一个根文件夹,然后是两个子文件夹,然后是xml目录,然后是xml文件。
我只知道根文件夹和xml目录的名称
下面的代码遍历所有目录,速度非常慢。有没有关于如何优化搜索的建议,特别是在已知目录结构的情况下
string[] files = Directory.GetFiles(@"\\somenetworkpath\rootFolder", "*.xml", SearchOption.AllDirectories);
是否有与xml文件夹相同级别的其他目录?如果是这样的话,你可能会加快搜索速度,如果你自己做的话,并从搜索中消除这个级别
System.IO.DirectoryInfo root = new System.IO.DirectoryInfo(rootPath);
List<System.IO.FileInfo> xmlFiles=new List<System.IO.FileInfo>();
foreach (System.IO.DirectoryInfo subDir1 in root.GetDirectories())
{
foreach (System.IO.DirectoryInfo subDir2 in subDir1.GetDirectories())
{
System.IO.DirectoryInfo xmlDir = new System.IO.DirectoryInfo(System.IO.Path.Combine(subDir2.FullName, "xml"));
if (xmlDir.Exists)
{
xmlFiles.AddRange(xmlDir.GetFiles("*.xml"));
}
}
}
System.IO.DirectoryInfo root=new System.IO.DirectoryInfo(rootPath);
List xmlFiles=新列表();
foreach(root.GetDirectories()中的System.IO.DirectoryInfo subDir1)
{
foreach(subDir1.GetDirectories()中的System.IO.DirectoryInfo subDir2)
{
System.IO.DirectoryInfo xmlDir=new System.IO.DirectoryInfo(System.IO.Path.Combine(subdri2.FullName,“xml”);
if(xmlDir.Exists)
{
AddRange(xmlDir.GetFiles(“*.xml”);
}
}
}
在C#中,我想不出比这更快的方法了,但是您是否为该文件系统启用了索引功能?您最有可能使用GetDirectory,首先获取“第一个子文件夹”列表,循环浏览这些目录,然后对子文件夹重复该过程,循环遍历它们,最后查找xml文件夹,最后搜索.xml文件
现在,对于性能来说,速度会有所不同,但是首先搜索目录,然后访问文件应该会有很大帮助
更新
好的,我做了一个快速的测试,你实际上可以比我想象的更进一步地优化它
下面的代码片段将搜索目录结构,并在整个目录树中找到所有“xml”文件夹
string startPath = @"C:\Testing\Testing\bin\Debug";
string[] oDirectories = Directory.GetDirectories(startPath, "xml", SearchOption.AllDirectories);
Console.WriteLine(oDirectories.Length.ToString());
foreach (string oCurrent in oDirectories)
Console.WriteLine(oCurrent);
Console.ReadLine();
如果你把它放到一个测试控制台应用程序中,你会看到它输出结果
现在,一旦你有了这个,只需在找到的每个目录中查找.xml文件。我能看到的唯一不同的方法是改变暴力强度搜索,并使用一些第三方或操作系统索引例程来加快返回速度。这样,搜索就可以从你的应用程序离线完成
但我也建议您尽可能寻找更好的方法来构造数据。在
FindFirstFile
/FindNextFile
/FindClose
上使用p/Invoke,并避免创建大量FileInfo实例的开销
但这将是一项艰难的工作(您必须自己处理文件、目录和递归)。因此,请尝试一些简单的方法(Directory.GetFiles()、Directory.GetDirectories())来开始工作,并使其正常工作。如果速度太慢,请查看备选方案(但总是测量,太容易使其变慢)。我创建了一个递归方法
GetFolders
,使用并行方法。ForEach
查找所有名为变量yourKeyword
List<string> returnFolders = new List<string>();
object locker = new object();
Parallel.ForEach(subFolders, subFolder =>
{
if (subFolder.ToUpper().EndsWith(yourKeyword))
{
lock (locker)
{
returnFolders.Add(subFolder);
}
}
else
{
lock (locker)
{
returnFolders.AddRange(GetFolders(Directory.GetDirectories(subFolder)));
}
}
});
return returnFolders;
List returnFolders=new List();
对象锁定器=新对象();
Parallel.ForEach(子文件夹,子文件夹=>
{
if(子文件夹.ToUpper().EndsWith(yourKeyword))
{
锁(储物柜)
{
returnFolders.Add(子文件夹);
}
}
其他的
{
锁(储物柜)
{
returnFolders.AddRange(GetFolders(Directory.GetDirectories(subFolder));
}
}
});
返回文件夹;
根据您的需要和配置,您可以使用Windows搜索索引:
根据您的配置,这可以大大提高性能。对于文件和目录搜索,我希望提供具有广泛搜索机会的多线程.NET库。 您可以在GitHub上找到有关库的所有信息: 如果您想下载,可以在以下位置下载: 如果你有任何问题,请问他们 工作非常快。你自己检查一下 这是一个演示示例,说明了如何使用它:
class Searcher
{
private static object locker = new object();
private FileSearcher searcher;
List<FileInfo> files;
public Searcher()
{
files = new List<FileInfo>();
}
public void Startsearch()
{
CancellationTokenSource tokenSource = new CancellationTokenSource();
searcher = new FileSearcher(@"C:\", (f) =>
{
return Regex.IsMatch(f.Name, @".*[Dd]ragon.*.jpg$");
}, tokenSource);
searcher.FilesFound += (sender, arg) =>
{
lock (locker) // using a lock is obligatorily
{
arg.Files.ForEach((f) =>
{
files.Add(f);
Console.WriteLine($"File location: {f.FullName}, \nCreation.Time: {f.CreationTime}");
});
if (files.Count >= 10)
searcher.StopSearch();
}
};
searcher.SearchCompleted += (sender, arg) =>
{
if (arg.IsCanceled)
Console.WriteLine("Search stopped.");
else
Console.WriteLine("Search completed.");
Console.WriteLine($"Quantity of files: {files.Count}");
};
searcher.StartSearchAsync();
}
}
类搜索器
{
私有静态对象锁定器=新对象();
私有文件搜索器;
列出文件;
公共搜索者()
{
文件=新列表();
}
公共无效Startsearch()
{
CancellationTokenSource tokenSource=新的CancellationTokenSource();
searcher=newfilesearcher(@“C:\”,(f)=>
{
返回Regex.IsMatch(f.Name,@“*[Dd]ragon.*.jpg$”;
},来源);
searcher.FilesFound+=(发件人,arg)=>
{
锁(储物柜)//使用锁是强制性的
{
arg.Files.ForEach((f)=>
{
添加(f);
WriteLine($“文件位置:{f.FullName},\n创建时间:{f.CreationTime}”);
});
如果(files.Count>=10)
searcher.StopSearch();
}
};
searcher.SearchCompleted+=(发件人,arg)=>
{
如果(参数已取消)
控制台.WriteLine(“搜索已停止”);
其他的
Console.WriteLine(“搜索已完成”);
WriteLine($“文件数量:{files.Count}”);
};
startsearchsync();
}
}
这是其他示例的一部分:
***
List<string> folders = new List<string>
{
@"C:\Users\Public",
@"C:\Windows\System32",
@"D:\Program Files",
@"D:\Program Files (x86)"
}; // list of search directories
List<string> keywords = new List<string> { "word1", "word2", "word3" }; // list of search keywords
FileSearcherMultiple multipleSearcher = new FileSearcherMultiple(folders, (f) =>
{
if (f.CreationTime >= new DateTime(2015, 3, 15) &&
(f.Extension == ".cs" || f.Extension == ".sln"))
foreach (var keyword in keywords)
if (f.Name.Contains(keyword))
return true;
return false;
}, tokenSource, ExecuteHandlers.InCurrentTask, true);
***
***
列表文件夹=新列表
{
@“C:\Users\Public”,
@“C:\Windows\System32”,
@“D:\程序文件”,
@“D:\Program Files(x86)”
}; // 搜索目录列表
列表关键字=新列表{“word1”、“word2”、“word3”};//搜索关键字列表
文件搜索多个多语言
List<FileInfo> files = FileSearcher.GetFilesFast(@"C:\Users", "*.xml");
private void btnSearch_Click(object sender, EventArgs e)
{
string userinput = txtInput.Text;
string sourceFolder = @"C:\mytestDir\";
string searchWord = txtInput.Text + ".pdf";
string filePresentCK = sourceFolder + searchWord;
if (File.Exists(filePresentCK))
{
pdfViewer1.LoadFromFile(sourceFolder+searchWord);
}
else if(! File.Exists(filePresentCK))
{
MessageBox.Show("Unable to Find file :" + searchWord);
}
txtInput.Clear();
}// end of btnSearch method