你如何处理大量的小文件?
Posted
技术标签:
【中文标题】你如何处理大量的小文件?【英文标题】:How do you deal with lots of small files? 【发布时间】:2010-09-12 01:36:46 【问题描述】:我正在开发的产品每天收集数千个读数,并将它们作为 64k 二进制文件存储在 NTFS 分区 (Windows XP) 上。经过一年的生产,单个目录中有超过 300000 个文件,并且数量还在不断增长。这使得从 Windows 资源管理器访问父/祖先目录非常耗时。
我已尝试关闭索引服务,但没有任何区别。我还考虑将文件内容移动到数据库/zip 文件/tarball 中,但单独访问这些文件对我们是有益的;基本上,这些文件仍然需要用于研究目的,研究人员不愿意处理其他任何事情。
有没有办法优化 NTFS 或 Windows 以便它可以处理所有这些小文件?
【问题讨论】:
NTFS performance and large volumes of files and directories 【参考方案1】:只要您告诉 NTFS 停止创建与 16 位 Windows 平台兼容的替代文件名,NTFS 实际上可以很好地处理目录中超过 10,000 个文件。默认情况下,NTFS 会自动为每个创建的文件创建一个“8 点 3”文件名。当目录中有许多文件时,这会成为一个问题,因为 Windows 会查看目录中的文件以确保它们创建的名称尚未使用。您可以通过将 NtfsDisable8dot3NameCreation 注册表值设置为 1 来禁用“8 点 3”命名。该值位于 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\FileSystem 注册表路径中。进行此更改是安全的,因为只有为非常旧的 Windows 版本编写的程序才需要“8 点 3”名称文件。
此设置需要重新启动才能生效。
【讨论】:
300,000 文件以上建议关闭 8 dot 3。 technet.microsoft.com/en-us/library/cc778996(WS.10).aspx 您可以在较新版本的 Windows 上从命令行更改行为,例如fsutil 8dot3name set 1
.
不确定它对 WinXP 的含义,但现在在 Win10 上该工具显示:This operation takes effect immediately (no reboot required)
【参考方案2】:
在目录中有 10,000 个文件后,NTFS 性能会严重下降。您所做的是在目录层次结构中创建一个附加级别,每个子目录有 10,000 个文件。
对于它的价值,这是 SVN 人员在version 1.5 中采用的方法。他们使用 1,000 个文件作为默认阈值。
【讨论】:
我知道很多人推荐这种方法,但我选择了这个答案,因为它引用了一个有信誉的软件项目。感谢您的所有回复。 您是否有链接解释为什么在 10,000 个文件后性能会严重下降? 有了NTFS,你可以在需要创建子文件夹之前处理上千万个文件***.com/a/291292/141172 @LawrenceBarsanti:SVN 并非设计为仅在 NTFS 上运行,而是在一系列文件系统上运行。较旧的文件系统遇到了需要比 NTFS 更快地创建子文件夹的问题。 请记住,最初的答案是 7 年,现在硬盘驱动器明显快了。【参考方案3】:性能问题是由单个目录中的大量文件引起的:一旦消除它,就应该没问题。这不是特定于 NTFS 的问题:事实上,在大型 UNIX 系统上的用户主目录/邮件文件中经常会遇到这种情况。
解决此问题的一个明显方法是将文件移动到名称基于文件名的文件夹中。假设您所有的文件都有相似长度的文件名,例如ABCDEFGHI.db、ABCEFGHIJ.db 等,创建如下目录结构:
ABC\
DEF\
ABCDEFGHI.db
EFG\
ABCEFGHIJ.db
使用这种结构,您可以根据文件名快速定位文件。如果文件名具有可变长度,请选择最大长度,并在前面加上零(或任何其他字符)以确定文件所属的目录。
【讨论】:
最好在目录名称中使用反向拆分 - 它会通过消除相似名称前缀来缩短最后一个目录内的搜索时间,例如:GHI\DEF\ABCDEFGHI.db【参考方案4】:过去我已经看到了巨大的改进,将文件拆分为嵌套的目录层次结构,例如,文件名的第一个然后是第二个字母;那么每个目录不包含过多的文件。但是,操作整个数据库仍然很慢。
【讨论】:
【参考方案5】:您可以尝试使用 Solid File System 之类的东西。
这为您提供了一个虚拟文件系统,应用程序可以像挂载物理磁盘一样挂载该文件系统。您的应用程序会看到许多小文件,但硬盘上只有一个文件。
http://www.eldos.com/solfsdrv/
【讨论】:
这是一个很酷的主意! EldoS 网站已从互联网上消失。 Torry.net 上似乎有一个(试用版?)版本(未经验证或防病毒测试)。【参考方案6】:过去我曾多次遇到过这个问题。我们尝试按日期存储,将文件压缩到日期以下,这样您就不会有很多小文件等。所有这些都是针对将数据作为大量小文件存储在 NTFS 上的真正问题的创可贴。
您可以转到 ZFS 或其他可以更好地处理小文件的文件系统,但仍要停下来询问您是否需要存储小文件。
在我们的案例中,我们最终进入了一个系统,即某个日期的所有小文件都以 TAR 类型的方式附加,并带有简单的分隔符来解析它们。磁盘文件从 120 万个减少到几千个。它们实际上加载得更快,因为 NTFS 不能很好地处理小文件,而且驱动器能够更好地缓存 1MB 文件。在我们的例子中,与实际存储和维护存储文件相比,找到文件正确部分的访问和解析时间最少。
【讨论】:
【参考方案7】:如果您可以计算文件的名称,则可以按日期将它们分类到文件夹中,以便每个文件夹仅包含特定日期的文件。您可能还想创建月份和年份层次结构。
另外,您能否将超过一年的文件移动到其他(但仍可访问)位置?
最后,再一次,这要求您能够计算名称,您会发现直接访问文件比尝试通过资源管理器打开文件要快得多。例如,说notepad.exe "P:\ath\to\your\filen.ame" 假设您知道所需文件的路径,而无需获取目录列表,从命令行实际上应该很快。
【讨论】:
【参考方案8】:一个常见的技巧是简单地创建一些子目录并将文件分开。
例如,Doxygen 是一个可以生成大量 html 页面的自动化代码文档程序,它可以选择创建两级深层目录层次结构。然后文件均匀分布在底部目录中。
【讨论】:
【参考方案9】:在单个目录中拥有数十万个文件确实会削弱 NTFS,而您对此无能为力。您应该重新考虑以更实用的格式存储数据,例如一个大压缩包或数据库。
如果你真的需要为每个阅读单独的文件,你应该将它们分类到几个子目录中,而不是将它们全部放在同一个目录中。您可以通过创建目录层次结构并根据文件名将文件放在不同的目录中来做到这一点。这样,您仍然可以只知道文件名来存储和加载文件。
我们使用的方法是取文件名的最后几个字母,将它们反转,并从中创建一个字母的目录。例如,考虑以下文件:
1.xml
24.xml
12331.xml
2304252.xml
你可以像这样将它们分类到目录中:
data/1.xml
data/24.xml
data/1/3/3/12331.xml
data/2/5/2/4/0/2304252.xml
此方案将确保您在每个目录中的文件永远不会超过 100 个。
【讨论】:
【参考方案10】:除了将文件放在子目录中..
就个人而言,我会开发一个应用程序来保持该文件夹的界面相同,即所有文件都显示为单独的文件。然后在应用程序后台实际获取这些文件并将它们组合成一个更大的文件(由于大小始终为 64k,因此获取您需要的数据应该相对容易)以摆脱您所拥有的混乱。
因此,您仍然可以让他们轻松访问他们想要的文件,还可以让您更好地控制所有内容的结构。
【讨论】:
【参考方案11】:考虑将它们推送到另一台服务器,该服务器使用对大量小文件更友好的文件系统(例如 Solaris w/ZFS)?
【讨论】:
【参考方案12】:如果数据有任何有意义的、分类的方面,您可以将它们嵌套在目录树中。我相信减速是由于一个目录中的文件数量,而不是文件本身的数量。
最明显的一般分组是按日期,它为您提供了一个三层嵌套结构(年、月、日),每个叶目录中的文件数量(1-3k)具有相对安全的界限。
即使您能够提高文件系统/文件浏览器的性能,听起来这也是您将在 2 年或 3 年内遇到的问题......只需查看 0.3-1 百万个文件的列表即可会产生成本,因此从长远来看,找到仅查看较小文件子集的方法可能会更好。
使用 'find' 之类的工具(在 cygwin 或 mingw 下)可以使浏览文件时不存在子目录树的问题。
【讨论】:
【参考方案13】:每天用时间戳重命名文件夹。
如果应用程序正在将文件保存到 c:\Readings 中,则设置计划任务以在午夜重命名 Reading 并创建一个新的空文件夹。
然后你会得到每天一个文件夹,每个文件夹包含几千个文件。
您可以将该方法进一步扩展为按月分组。例如,C:\Reading 变为 c:\Archive\September\22。
您必须注意时间安排,以确保在产品保存到该文件夹时不会尝试重命名该文件夹。
【讨论】:
【参考方案14】:要创建一个可以扩展到大量未知文件的文件夹结构,我喜欢以下系统:
将文件名拆分为固定长度的片段,然后为除最后一个片段之外的每个片段创建嵌套文件夹。
此系统的优点是文件夹结构的深度仅与文件名的长度一样深。因此,如果您的文件是按数字序列自动生成的,那么结构就很深了。
12.jpg -> 12.jpg
123.jpg -> 12\123.jpg
123456.jpg -> 12\34\123456.jpg
这种方法确实意味着文件夹包含文件和子文件夹,但我认为这是一个合理的权衡。
这是一个漂亮的 PowerShell 单线器,让你继续前进!
$s = '123456'
-join (( $s -replace '(..)(?!$)', '$1\' -replace '[^\\]*$','' ), $s )
【讨论】:
以上是关于你如何处理大量的小文件?的主要内容,如果未能解决你的问题,请参考以下文章