我有一个包含近1400万个以*.wav格式存储的音频样本的目录。
全部存储在同一级别,没有子目录。
当我使用DirectoryInfo.GetFiles()
在该文件夹上循环遍历文件时,整个应用程序会冻结数分钟!
还有其他方法可以完成这个任务吗?也许每次读取1000个文件进行处理,然后再获取接下来的1000个文件,如此类推?
您尝试过 DirectoryInfo 类的 EnumerateFiles 方法吗?
如 MSDN 所说:
EnumerateFiles
和GetFiles
方法的区别在于:当使用EnumerateFiles
时,您可以在整个FileInfo
对象集合返回之前开始枚举;而当您使用GetFiles
时,必须等待整个FileInfo
对象数组被返回后才能访问该数组。因此,当您处理许多文件和目录时,EnumerateFiles
可能更有效率。
string dir;
Directory.GetFiles
/ Directory.EnumerateFiles
返回字符串new DirectoryInfo(dir).getFiles
/ new DirectoryInfo(dir).EnumerateFiles
返回 FileInfo - teamchongDirectory.EnumerateFiles(...)
返回的是IEnumerable<string>
类型(而不是Directory.GetFiles(...)
返回的string[]
),因此它可以流式传输文件而不需要缓存全部内容。foreach(var file in Directory.EnumerateFiles(path)) {
// ...
}
你遇到了Windows文件系统本身的限制。当一个目录中的文件数量增长到一定水平时(1400万已经远远超出这个阈值),访问该目录变得极其缓慢。无论你是一次读取一个文件还是1000个文件,都只是访问目录而已。
解决方法之一是创建子目录并将文件分组存储。如果每个目录中有1000-5000个文件(这只是猜测,但可以根据具体情况进行实验),那么打开/创建/删除文件时应该有良好的性能表现。
这就是为什么像Doxygen这样的应用程序,为每个类创建一个文件时,会遵循此方案并将所有内容放入两级随机命名的子目录中。
使用Win32 Api FindFile函数可以在不阻塞应用程序的情况下完成操作。
您还可以在System.Threading.Task (TPL)中调用Directory.GetFiles,以防止UI冻结。
享受。
public List<string> LoadPathToAllFiles(string pathToFolder, int numberOfFilesToReturn)
{
var dirInfo = new DirectoryInfo(pathToFolder);
var firstFiles = dirInfo.EnumerateFiles().Take(numberOfFilesToReturn).ToList();
return firstFiles.Select(l => l.FullName).ToList();
}
我经常遇到访问单个目录中大文件的问题。子目录是一个不错的选择,但有时它们也无法提供太多帮助。现在我所做的是创建一个索引文件——一个包含目录中所有文件名称的文本文件(前提是我正在创建该目录中的文件)。然后,我会读取索引文件,并打开目录中的实际文件进行处理。
DirectoryInfo.GetFiles()
也是可怕的。它会锁定所有文件并阻止其他人访问最近创建的SAN文件。我们从未找到过非阻塞解决方案。 - SliverNinja - MSFT