我有一些包含测试数据的目录,每个目录通常有超过200,000个小(~4k)文件.
我使用以下C#代码来获取目录中的文件数:
int fileCount = System.IO.Directory.GetFiles(@"C:\SomeDirectory").Length;
Run Code Online (Sandbox Code Playgroud)
然而,这非常非常缓慢 - 我可以使用任何替代方案吗?
每个文件夹包含一天的数据,我们将有大约18个月的目录(~550个目录).我也对通过将平面目录结构重新编写为更嵌套的结构而发现的性能增强非常感兴趣.
Bev*_*van 10
您获得的代码很慢,因为它首先获取所有可用文件的数组,然后获取该数组的长度.
但是,您几乎肯定不会找到任何比这更快的解决方案.
为什么?
访问控制.
目录中的每个文件都可能具有访问控制列表 - 这可能会阻止您查看该文件.
操作系统本身不能只是说"嘿,这里有100个文件条目",因为它们中的一些可能代表您不允许知道的文件存在 - 它们根本不应该向您显示.因此操作系统本身必须遍历文件,逐个文件检查访问权限.
有关此类事情的详细讨论,请参阅The Old New Thing的两篇帖子:
[另外,如果您想提高包含大量文件的目录的性能,请严格限制为8.3文件名.不,我不是在开玩笑 - 它更快,因为操作系统本身不需要生成8.3文件名,并且因为使用的算法是脑死亡.试试基准,你会看到.
仅供参考,.NET 4包含一种新方法Directory.EnumerateFiles,它可以完全满足您的需求.您可能没有使用.NET 4,但无论如何它都值得记住!
编辑:我现在意识到OP需要NUMBER个文件.但是,这个方法非常有用我在这里保留这篇文章.
我对包含(我们认为)~300,000个文件的目录有一个非常类似的问题.
在搞乱了许多加速访问的方法(所有不成功)之后,我们通过将目录重组为更加分层的方式解决了访问问题.
我们通过创建a-z代表文件第一个字母的目录,然后创建每个目录的子目录,也包含a-z文件的第二个字母来完成此操作.然后我们将文件插入相关目录中
例如
gbp32.dat
Run Code Online (Sandbox Code Playgroud)
进入
g/b/gbp32.dat
Run Code Online (Sandbox Code Playgroud)
并适当地重写了我们的文件访问例程.这产生了巨大的差异,这是相对微不足道的(我认为我们使用10行Perl脚本移动每个文件)
不使用 System.IO.Directory 命名空间,就没有。您必须找到一种查询目录的方法,而不涉及创建大量文件列表。
这似乎是 Microsoft 的一个疏忽,Win32 API 始终具有可以对目录中的文件进行计数的功能。
您可能还需要考虑拆分目录。我无法理解如何管理包含 200,000 个文件的目录:-)
更新:
约翰·桑德斯在评论中提出了一个很好的观点。我们已经知道(通用)文件系统无法很好地处理这种级别的存储。能够处理大量小“文件”的一件事就是数据库。
如果您可以识别每个文件的密钥(例如,包含日期、时间和客户编号),则应将这些文件注入数据库中。大多数专业数据库应该可以轻松处理 4K 记录大小和 1.08 亿行(200,000 行/天 * 30 天/月 * 18 个月)。我知道 DB2/z 会把它当作早餐。
然后,当您需要将一些测试数据提取到文件中时,您可以使用一个脚本/程序将相关记录提取到文件系统中。然后运行测试以成功完成并删除文件。
这应该使您的具体问题很容易解决:
select count(*) from test_files where directory_name = '/SomeDirectory'
Run Code Online (Sandbox Code Playgroud)
当然,假设您在 Directory_name 上有一个索引。