更快(最快?)的方式来获取超过200,000个文件的目录中的文件数量

时间:2009-07-28 09:24:00

标签: .net file-io

我有一些包含测试数据的目录,每个目录通常有超过200,000个小(~4k)文件。

我使用以下C#代码来获取目录中的文件数:

int fileCount = System.IO.Directory.GetFiles(@"C:\SomeDirectory").Length;

然而,这非常非常缓慢 - 有什么替代品我可以使用吗?

修改

每个文件夹包含一天的数据,我们将有大约18个月的目录(~550个目录)。我对通过将平面目录结构重新编写为更嵌套的结构而发现的性能增强非常感兴趣。

10 个答案:

答案 0 :(得分:10)

您获得的代码很慢,因为它首先获取所有可用文件的数组,然后获取该数组的长度。

但是,你几乎肯定不会找到任何比这更快的解决方案。

为什么?

访问控件。

目录中的每个文件可能都有一个访问控制列表 - 这可能会阻止您查看该文件。

操作系统本身不能只说“嘿,此处有100个文件条目”,因为其中一些可能代表您不允许知道存在的文件 - 它们不应该在所有。因此操作系统本身必须遍历文件,逐个文件检查访问权限。

有关此类内容的详细讨论,请参阅The Old New Thing中的两篇帖子:

[另外,如果您想提高包含大量文件的目录的性能,请严格限制为8.3文件名。不,我不是在开玩笑 - 它更快,因为操作系统本身不需要生成8.3文件名,并且因为使用的算法是脑死亡。试试基准,你会看到。]

答案 1 :(得分:8)

仅供参考,.NET 4包含一种新方法Directory.EnumerateFiles完全符合您的需要非常棒。您可能没有使用.NET 4,但无论如何它都值得记住!

编辑:我现在意识到OP需要NUMBER个文件。但是,这个方法非常有用我在这里保留这篇文章。

答案 2 :(得分:6)

我的目录中包含(我们认为)~300,000个文件的问题非常类似。

在搞乱了许多加速访问的方法(所有不成功)之后,我们通过将目录重组为更加分层的方式解决了访问问题。

我们通过创建代表文件第一个字母的目录a-z,然后创建每个目录的子目录,同时包含文件第二个字母的a-z来完成此操作。然后我们将文件插入相关目录

e.g。

gbp32.dat

进去了

g/b/gbp32.dat

并适当地重写了我们的文件访问例程。这造成了大量的差异,并且它相对微不足道(我认为我们使用10行Perl脚本移动每个文件)

答案 3 :(得分:4)

您可以使用System.Management和WMI的类“cim_datafile”,只需在WMI中运行以下查询,您也可以使用Linq to Wmi但我没有尝试

select * from cim_datafile where drive='c:' and path='\\SomeDirectory\\' 

我想它会更快地运作

答案 4 :(得分:4)

文件系统不是为此布局设计的。如果要处理性能问题,则必须重新组织它(每个文件夹的文件数量更少)。

答案 5 :(得分:4)

不使用System.IO.Directory命名空间,没有。您必须找到一种查询目录的方法,该方法不涉及创建大量文件列表。

这似乎是微软的一个疏忽,Win32 API总是有可以计算目录中文件的函数。

您可能还想考虑拆分目录。如何管理200,000文件目录超出了我的范围: - )

更新

John Saunders在评论中提出了一个很好的观点。我们已经知道(通用)文件系统不能很好地处理这种级别的存储。 配备处理大量小“文件”的一件事是数据库。

如果您可以为每个密钥标识密钥(例如,包含日期,小时和客户编号),则应将这些文件注入数据库。大多数专业数据库都应该能够轻松处理4K记录大小和1.08亿行(200,000行/天* 30天/月* 18个月)。我知道DB2 / z会在早餐时咀嚼它。

然后,当您需要将一些测试数据提取到文件时,您有一个脚本/程序,它只是将相关记录提取到文件系统中。然后运行测试以成功完成并删除文件。

这应该使您的具体问题变得非常容易:

select count(*) from test_files where directory_name = '/SomeDirectory'

假设您在directory_name上有索引。

答案 6 :(得分:3)

如果您不害怕调用win32函数,可能值得尝试FIndFirstFile然后使用FindNextFile进行迭代。这节省了分配所有这些字符串的开销以获得计数。

答案 7 :(得分:1)

每天午夜创建一个索引。找到一个文件会非常快。计算文件数量同样重要。

如果我看对了,你每天都有一个目录。如果您今天收到的所有文件都在今天的地图中,那么可以改进此系统。只需在午夜索引前一天的目录。

答案 8 :(得分:0)

如果我使用缓慢的高级语言,并且可移植性不是一个大问题,我很想尝试调用外部程序(例如`ls | wc`.first.to_i 如果使用ruby然后我会检查它是否能更好地完成工作。

答案 9 :(得分:0)

如果只需要文件计数,我发现使用'EnumerateFiles()'比使用'GetFiles()'要快得多:

C:\Users\offic>py -m pip install --user pyscreeze
Requirement already satisfied: pyscreeze in c:\users\offic\pycharmprojects\test\venv\lib\site-packages (0.1.26)
Requirement already satisfied: Pillow>=5.2.0 in c:\users\offic\pycharmprojects\test\venv\lib\site-packages (from pyscreeze) (7.1.1)