关于文件系统:我可以在目录中放入多少个文件?

How many files can I put in a directory?

我在一个目录中保存了多少文件有关系吗?如果是这样,一个目录中有多少文件太多,那么拥有太多文件会产生什么影响?(这在Linux服务器上。)

背景:我有一个相册网站,上传的每一张图片都被重命名为一个8位的ID(比如,a58f375c.jpg)。这是为了避免文件名冲突(例如,如果上载了大量"img001.jpg"文件)。原始文件名和任何有用的元数据都存储在数据库中。现在,我在图像目录中大约有1500个文件。这使得在目录中列出文件(通过ftp或ssh客户机)需要几秒钟的时间。但我看不出除此之外还有什么影响。尤其是,似乎对向用户提供图像文件的速度没有任何影响。

我已经考虑过通过创建16个子目录来减少图像的数量:0-9和a-f。然后我会根据文件名的第一个十六进制数字将图像移动到子目录中。但我不确定是否有任何理由这样做,除了通过ftp/ssh偶尔列出目录。


FAT32:

  • 最大文件数:268173300
  • 每个目录的最大文件数:216-1(65535)
  • 最大文件大小:2 Gib-1(不带LFS),4 Gib-1(带LFS)

NTFS:

  • 最大文件数:232-1(4294967295)
  • 最大文件大小
    • 实现:244-26字节(16 tib-64 kib)
    • 理论上:264-26字节(16 EIB-64 kib)
  • 最大卷大小
    • 实施:232-1个集群(256个TIB-64 kib)
    • 理论上:264-1个集群(1 Yib-64 kib)

EXT2:

  • 最大文件数:1018
  • 每个目录的最大文件数:~1.3次1020(超过10000的性能问题)
  • 最大文件大小
    • 16 gib(块大小为1 kib)
    • 256 gib(块大小为2 kib)
    • 2 tib(块大小为4 kib)
    • 2 tib(块大小为8 kib)
  • 最大卷大小
    • 4 Tib(块大小为1 kib)
    • 8 tib(块大小为2 kib)
    • 16 tib(块大小为4 kib)
    • 32 tib(块大小为8 kib)

EXT3:

  • 最大文件数:min(volumeSize/213,numberofBlocks)
  • 最大文件大小:与ext2相同
  • 最大卷大小:与ext2相同

Ext4:

  • 最大文件数:232-1(4294967295)
  • 每个目录的最大文件数:无限制
  • 最大文件大小:244-1字节(16 tib-1)
  • 最大卷大小:248-1字节(256 tib-1)


我在一个ext3目录中有超过800万个文件。libc readdir(),由findls和本线程中讨论的大多数其他方法用于列出大目录。

在这种情况下,lsfind速度慢的原因是readdir()一次只读取32k个目录条目,因此在速度慢的磁盘上,列出一个目录需要多次读取。有一个解决这个速度问题的方法。关于它,我写了一篇非常详细的文章:http://www.olark.com/spw/2011/08/you-can-list-a-directory-with-800-million-files-but-not-with-ls/

关键是:直接使用getdents()--http://www.kernel.org/doc/man-pages/online/pages/man2/getdents.2.html,而不是基于libc readdir()的任何内容,这样在从磁盘读取目录条目时,您就可以指定缓冲区大小。


它稍微依赖于Linux服务器上使用的特定文件系统。目前的默认目录是ext3和dir_索引,这使得搜索大型目录的速度非常快。

所以速度不应该是一个问题,除了你已经注意到的问题,也就是说列表需要更长的时间。

一个目录中的文件总数有限制。我似乎记得它肯定能处理32000个文件。


我有一个目录,里面有88914个文件。像你自己一样,它用于存储缩略图和Linux服务器。

通过ftp或php函数列出的文件速度很慢是的,但显示该文件时也会影响性能。例如,www.website.com/thumbdir/gh3hg4h2b4h234b3b3h2h2h34b3h2.jpg的等待时间为200-400毫秒。与我在另一个站点上的目录中的大约100个文件相比,图像在等待大约40毫秒后显示。

我给出了这个答案,因为大多数人刚刚写下了目录搜索功能的运行方式,你不会在一个拇指文件夹上使用这个功能——只是静态显示文件,但会对文件实际使用方式的性能感兴趣。


请记住,在Linux上,如果目录中的文件太多,shell可能无法展开通配符。我有一个在Linux上托管的相册的问题。它将所有调整大小的图像存储在一个目录中。虽然文件系统可以处理许多文件,但shell无法处理。示例:

1
2
-shell-3.00$ ls A*
-shell: /bin/ls: Argument list too long

1
2
-shell-3.00$ chmod 644 *jpg
-shell: /bin/chmod: Argument list too long


我正在处理一个类似的问题。我们有一个层次目录结构,并使用图像ID作为文件名。例如,在

1
..../45/67/1234567_<...>.jpg

使用最后4位数字确定文件的位置。

有了几千张图片,您可以使用一个层次结构。我们的系统管理员建议在任何给定的目录(ext3)中不超过两千个文件,以提高效率/备份/无论他考虑到什么其他原因。


就其价值而言,我刚刚在一个包含1000000个文件的ext4文件系统上创建了一个目录,然后通过Web服务器随机访问这些文件。我没有注意到访问那些超过(比如说)只有10个文件在那里的额外费用。

这与几年前我在ntfs上做这件事的经验完全不同。


我遇到的最大问题是32位系统。一旦你通过了一定数量,像"ls"这样的工具就会停止工作。

一旦你通过了这个屏障,尝试对这个目录做任何事情都会成为一个巨大的问题。


它实际上取决于所使用的文件系统,以及一些标志。

例如,ext3可以有数千个文件;但是在几千个文件之后,它的速度非常慢。主要是在列出一个目录时,也可以在打开一个文件时。几年前,它获得了"htree"选项,这大大缩短了获得给定文件名的inode所需的时间。

就个人而言,我使用子目录将大多数级别保持在1000个左右的项目之下。在您的例子中,我将创建256个目录,ID的最后两个十六进制数字。使用最后一个而不是第一个数字,这样您就可以获得负载平衡。


它完全依赖于文件系统。许多现代的文件系统使用合适的数据结构来存储目录的内容,但是旧的文件系统通常只是将条目添加到列表中,因此检索文件是一个O(N)操作。

即使文件系统做得对,列出目录内容并进行O(n^2)排序的程序仍然是绝对可能的,因此为了安全起见,我总是将每个目录的文件数限制在不超过500。


如果实现目录分区方案所需的时间很短,那么我赞成它。第一次您必须调试一个涉及通过您将理解的控制台操作10000个文件目录的问题。

例如,f-spot将照片文件存储为yyyymmddfilename.ext,这意味着手动操作~20000张照片集时必须处理的最大目录大约是800个文件。这也使得文件更容易从第三方应用程序浏览。永远不要假设你的软件是唯一能访问你的软件文件的东西。


问题归结到你将如何处理这些文件。

在Windows下,任何文件超过2K的目录都会在资源管理器中缓慢打开。如果它们都是图像文件,那么超过1K的文件在缩略图视图中的打开速度会非常慢。

有一次,制度规定的限额是32767。它现在更高了,但在大多数情况下,即使这样也太多的文件一次无法处理。


事实上,ext3确实有目录大小限制,它们取决于文件系统的块大小。没有每个目录的"max number"文件,而是每个目录的"max number of blocks used to store file entries"。具体来说,目录本身的大小不能超过高度为3的B-树,并且目录树的扇出取决于块大小。有关详细信息,请参阅此链接。

https://www.mail-archive.com/[email protected]/msg01944.html

我最近在一个格式化为2K块的文件系统上被咬了一口,当我从另一个ext3文件系统复制时,它莫名其妙地得到了目录完整的内核消息warning: ext3_dx_add_entry: Directory index full!。在我的例子中,只有480000个文件的目录无法复制到目的地。


我记得我运行了一个程序,在输出端创建了大量的文件。这些文件按每个目录30000个进行排序。我不记得当我必须重用生成的输出时有任何读取问题。它在一台32位的UbuntuLinux笔记本电脑上,即使是Nautilus也显示了目录内容,尽管几秒钟之后。

ext3文件系统:64位系统上的类似代码可以很好地处理每个目录64000个文件。


我也遇到了类似的问题。我试图访问一个包含10000多个文件的目录。构建文件列表并对任何文件运行任何类型的命令花费的时间太长。

我想出了一个小PHP脚本来为自己做这个,并试图找到一种方法来防止它在浏览器中超时。

下面是我为解决这个问题而编写的PHP脚本。

列出目录中文件的ftp文件太多

它如何帮助别人


我也有同样的问题。尝试在ext4的Ubuntu服务器中存储数百万个文件。结束了我自己的基准测试。发现flat目录在使用简单的同时性能更好:

benchmark

写了一篇文章。


我喜欢和阿曼迪诺一样的方式。为此,我在php中使用这个小函数将id转换成一个文件路径,每个目录产生1000个文件:

1
2
3
4
5
6
7
function dynamic_path($int) {
    // 1000 = 1000 files per dir
    // 10000 = 10000 files per dir
    // 2 = 100 dirs per dir
    // 3 = 1000 dirs per dir
    return implode('/', str_split(intval($int / 1000), 2)) . '/';
}

或者,如果要使用字母数字,可以使用第二个版本:

1
2
3
4
5
6
7
function dynamic_path2($str) {
    // 26 alpha + 10 num + 3 special chars (._-) = 39 combinations
    // -1 = 39^2 = 1521 files per dir
    // -2 = 39^3 = 59319 files per dir (if every combination exists)
    $left = substr($str, 0, -1);
    return implode('/', str_split($left ? $left : $str[0], 2)) . '/';
}

结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<?php
$files = explode(',', '1.jpg,12.jpg,123.jpg,999.jpg,1000.jpg,1234.jpg,1999.jpg,2000.jpg,12345.jpg,123456.jpg,1234567.jpg,12345678.jpg,123456789.jpg');
foreach ($files as $file) {
    echo dynamic_path(basename($file, '.jpg')) . $file . PHP_EOL;
}
?>

1/1.jpg
1/12.jpg
1/123.jpg
1/999.jpg
1/1000.jpg
2/1234.jpg
2/1999.jpg
2/2000.jpg
13/12345.jpg
12/4/123456.jpg
12/35/1234567.jpg
12/34/6/12345678.jpg
12/34/57/123456789.jpg

<?php
$files = array_merge($files, explode(',', 'a.jpg,b.jpg,ab.jpg,abc.jpg,ddd.jpg,af_ff.jpg,abcd.jpg,akkk.jpg,bf.ff.jpg,abc-de.jpg,abcdef.jpg,abcdefg.jpg,abcdefgh.jpg,abcdefghi.jpg'));
foreach ($files as $file) {
    echo dynamic_path2(basename($file, '.jpg')) . $file . PHP_EOL;
}
?>

1/1.jpg
1/12.jpg
12/123.jpg
99/999.jpg
10/0/1000.jpg
12/3/1234.jpg
19/9/1999.jpg
20/0/2000.jpg
12/34/12345.jpg
12/34/5/123456.jpg
12/34/56/1234567.jpg
12/34/56/7/12345678.jpg
12/34/56/78/123456789.jpg
a/a.jpg
b/b.jpg
a/ab.jpg
ab/abc.jpg
dd/ddd.jpg
af/_f/af_ff.jpg
ab/c/abcd.jpg
ak/k/akkk.jpg
bf/.f/bf.ff.jpg
ab/c-/d/abc-de.jpg
ab/cd/e/abcdef.jpg
ab/cd/ef/abcdefg.jpg
ab/cd/ef/g/abcdefgh.jpg
ab/cd/ef/gh/abcdefghi.jpg

如您所见,对于$int版本,每个文件夹最多包含1000个文件,最多包含99个目录,其中包含1000个文件和99个目录…

但不要忘了,对于许多目录来说,备份过程都会变慢。每个目录可以测试1000到10000个文件,但是不要添加太多,因为如果您想逐文件读取目录文件(ftp客户机、文件读取功能等),您将有很长的访问时间。

最后,您应该考虑如何减少文件总量。根据您的目标,您可以使用css sprites组合多个小图像,如头像、图标、笑脸等。或者,如果您使用许多小的非媒体文件,请考虑组合它们,例如以json格式。在我的例子中,我有数千个迷你缓存,最后我决定将它们组合成10个一包。


我尊重这并不能完全回答你的问题,即多少太多,但解决长期问题的一个想法是,除了存储原始文件元数据之外,还存储它存储在磁盘上的哪个文件夹—规范化这段元数据。一旦一个文件夹超出了性能、美观或其他原因所能承受的限制,您只需创建第二个文件夹并开始将文件放在那里…


上面大多数的答案都没有显示出原始问题没有"一刀切"的答案。

在当今的环境中,我们有大量不同的硬件和软件——有些是32位的,有些是64位的,有些是尖端的,有些是经过考验的,而且是真实可靠的,永不改变。此外,还有各种较旧和较新的硬件、较旧和较新的操作系统、不同的供应商(Windows、Unixes、Apple等)以及大量的实用程序和服务器。随着硬件的改进和软件的64位兼容性的转换,使得这个庞大而复杂的世界中的所有部分都能很好地适应快速变化的步伐,这必然会有相当大的延迟。

我不知道怎么解决问题。解决方案是研究可能性,然后通过反复试验找出最适合您特定需求的方案。每个用户必须确定什么对他们的系统有效,而不是使用cookie-cutter方法。

例如,我有一个媒体服务器,其中包含一些非常大的文件。结果只有大约400个文件填满了一个3 TB的驱动器。仅使用了1%的inode,但使用了95%的总空间。其他人,有很多小文件,可能会用完inode,然后他们接近填补空间。(根据经验,在ext4文件系统上,每个文件/目录使用一个inode。)虽然理论上目录中可能包含的文件总数几乎是无限的,但实用性决定了整体使用决定了实际的单位,而不仅仅是文件系统功能。

我希望以上所有不同的答案都能促进思考和解决问题,而不是成为前进的不可逾越的障碍。


不是答案,只是一些建议。

选择更合适的FS(文件系统)。从历史的角度来看,你所有的问题都是明智的,曾经是金融服务社几十年来发展的核心。我的意思是更现代的FS更好地支持您的问题。首先根据您在fs列表中的最终目的创建一个比较决策表。

我认为是时候改变你的模式了。所以我个人建议使用分布式系统感知的FS,这意味着在大小、文件数量等方面完全没有限制,否则您迟早会遇到新的意外问题。

我不确定是否能工作,但是如果你没有提到一些实验,可以尝试一下你当前文件系统上的AUF。我想它可以将多个文件夹模拟为一个虚拟文件夹。

要克服硬件限制,可以使用RAID-0。


没有一个数字是"太多",只要它不超过操作系统的限制。然而,不管操作系统是什么,目录中的文件越多,访问任何单个文件所需的时间就越长。在大多数操作系统中,性能是非线性的,因此在10000个文件中查找一个文件所需的时间比在1000个文件中查找一个文件所需的时间长10倍以上。

与目录中的许多文件相关联的次要问题包括通配符扩展失败。为了降低风险,您可以考虑按上载日期或其他一些有用的元数据对目录进行排序。