606

我在一个目录中保留多少个文件是否重要?如果是这样,一个目录中有多少文件太多了,文件太多有什么影响?(这是在 Linux 服务器上。)

背景:我有一个相册网站,上传的每张图片都被重命名为一个 8 位十六进制数字的 id(比如 a58f375c.jpg)。这是为了避免文件名冲突(例如,如果上传了很多“IMG0001.JPG”文件)。原始文件名和任何有用的元数据都存储在数据库中。现在,我在 images 目录中有大约 1500 个文件。这使得列出目录中的文件(通过 FTP 或 SSH 客户端)需要几秒钟。但除此之外,我看不到它有任何影响。特别是,图像文件提供给用户的速度似乎没有任何影响。

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

4

22 回答 22

802

FAT32

  • 最大文件数:268,173,300
  • 每个目录的最大文件数:2 16  - 1 (65,535)
  • 最大文件大小:2 GiB - 1 不带LFS,4 GiB - 1 带

NTFS

  • 最大文件数:2 32  - 1 (4,294,967,295)
  • 最大文件大小
    • 实现:2 44  - 2 6字节(16 TiB - 64 KiB)
    • 理论:2 64  - 2 6字节(16 EiB - 64 KiB)
  • 最大卷大小
    • 实施:2 32  - 1 个集群 (256 TiB - 64 KiB)
    • 理论:2 64  - 1 个集群(1 YiB - 64 KiB)

分机2

  • 最大文件数:10 18
  • 每个目录的最大文件数:~1.3 × 10 20(超过 10,000 个性能问题)
  • 最大文件大小
    • 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)

分机3

  • 最大文件数:min(volumeSize / 2 13 , numberOfBlocks)
  • 最大文件大小:与 ext2 相同
  • 最大卷大小:与 ext2 相同

分机4

  • 最大文件数:2 32  - 1 (4,294,967,295)
  • 每个目录的最大文件数:无限制
  • 最大文件大小:2 44  - 1 字节 (16 TiB - 1)
  • 最大卷大小:2 48  - 1 字节 (256 TiB - 1)
于 2009-01-21T19:16:51.000 回答
205

我在一个 ext3 目录中有超过 800 万个文件。readdir()使用的findlibc以及ls该线程中讨论的大多数其他方法来列出大型目录。

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

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

于 2011-08-11T20:19:45.087 回答
74

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

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

我已经给出了这个答案,因为大多数人刚刚编写了目录搜索功能将如何执行,您不会在拇指文件夹上使用它 - 只是静态显示文件,但会对文件的实际使用方式感兴趣.

于 2012-07-07T08:33:59.503 回答
57

这在一定程度上取决于 Linux 服务器上使用的特定文件系统。现在默认是带有 dir_index 的 ext3,这使得搜索大目录非常快。

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

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

于 2009-01-21T19:07:58.007 回答
49

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

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

或者

-shell-3.00$ chmod 644 *jpg
-shell: /bin/chmod: Argument list too long
于 2009-01-21T19:57:55.737 回答
27

我现在正在处理类似的问题。我们有一个分层目录结构,并使用图像 ID 作为文件名。例如,将带有的图像id=1234567放置在

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

使用最后 4 位数字来确定文件的去向。

对于几千张图像,您可以使用一层层次结构。我们的系统管理员建议在任何给定目录(ext3)中不要超过几千个文件,以提高效率/备份/他想到的任何其他原因。

于 2009-01-21T20:52:13.880 回答
27

值得一提的是,我只是在一个ext4包含 1,000,000 个文件的文件系统上创建了一个目录,然后通过 Web 服务器随机访问这些文件。我没有注意到访问那些(比如说)只有 10 个文件的人有任何溢价。

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

于 2013-11-10T18:39:16.323 回答
14

我一直有同样的问题。试图在 ext4 的 Ubuntu 服务器中存储数百万个文件。结束运行我自己的基准测试。发现平面目录的性能更好,同时使用起来更简单:

基准

写了一篇文章

于 2018-12-22T03:42:32.657 回答
13

我遇到的最大问题是在 32 位系统上。一旦您通过了某个数字,“ls”之类的工具就会停止工作。

一旦你越过了这个障碍,试图对那个目录做任何事情就会变成一个大问题。

于 2009-01-21T19:01:04.323 回答
10

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

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

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

于 2009-01-21T19:08:12.843 回答
8

如果实施目录分区方案所涉及的时间最少,我赞成它。第一次调试涉及通过控制台操作 10000 个文件目录的问题时,您会理解的。

例如,F-Spot 将照片文件存储为 YYYY\MM\DD\filename.ext,这意味着我在手动处理 ~20000 张照片时必须处理的最大目录大约是 800 个文件。这也使文件更容易从第三方应用程序中浏览。永远不要假设您的软件是唯一会访问您的软件文件的东西。

于 2009-01-21T19:55:10.143 回答
7

它绝对取决于文件系统。许多现代文件系统使用体面的数据结构来存储目录的内容,但较旧的文件系统通常只是将条目添加到列表中,因此检索文件是 O(n) 操作。

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

于 2009-01-21T20:08:12.127 回答
6

ext3 实际上确实有目录大小限制,它们取决于文件系统的块大小。没有每个目录的“最大文件数”,而是每个目录的“用于存储文件条目的最大块数”。具体来说,目录本身的大小不能超过高度为 3 的 b-tree,并且树的扇出取决于块大小。有关详细信息,请参阅此链接。

https://www.mail-archive.com/cwelug@googlegroups.com/msg01944.html

我最近在一个用 2K 块格式化的文件系统上被这个问题所困扰,warning: ext3_dx_add_entry: Directory index full!当我从另一个 ext3 文件系统复制时,它莫名其妙地得到了目录完整的内核消息。就我而言,只有 480,000 个文件的目录无法复制到目标位置。

于 2014-01-21T22:24:43.893 回答
5

问题归结为您将如何处理这些文件。

在 Windows 下,任何文件超过 2k 的目录在资源管理器中对我来说打开速度都很慢。如果它们都是图像文件,超过 1k 的文件往往在缩略图视图中打开速度很慢。

有一次,系统强加的限制是 32,767。现在更高了,但即便如此,在大多数情况下,一次处理的文件也太多了。

于 2009-01-21T19:07:56.540 回答
5

“取决于文件系统”
一些用户提到性能影响取决于使用的文件系统。当然。像 EXT3 这样的文件系统可能非常慢。但是,即使您使用 EXT4 或 XFS,您也无法阻止通过或通过外部连接(如 FTP)列出文件夹lsfind变得越来越慢。

解决方案我更喜欢与@armandino
相同的方式。为此,我在 PHP 中使用这个小函数将 ID 转换为文件路径,每个目录生成 1000 个文件:

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)) . '/';
}

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

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)) . '/';
}

结果:

<?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-version 中看到的那样,每个文件夹最多包含 1000 个文件和最多 99 个目录,其中包含 1000 个文件和 99 个目录......

但不要忘记,许多目录会导致相同的性能问题!

最后,您应该考虑如何减少总文件量。根据您的目标,您可以使用 CSS 精灵来组合多个小图像,如头像、图标、表情符号等,或者如果您使用许多小型非媒体文件,请考虑将它们组合成 JSON 格式。就我而言,我有数千个迷你缓存,最后我决定将它们组合成 10 个一包。

于 2015-04-17T19:32:38.773 回答
5

上面的大多数答案都没有表明原始问题没有“一刀切”的答案。

在今天的环境中,我们拥有大量不同的硬件和软件——有些是 32 位的,有些是 64 位的,有些是最先进的,有些是久经考验的——可靠且永不改变。除此之外,还有各种较旧和较新的硬件、较旧和较新的操作系统、不同的供应商(Windows、Unix、Apple 等)以及随之而来的无数实用程序和服务器。随着硬件的改进和软件转换为 64 位兼容性,让这个庞大而复杂的世界的所有部分与快速变化的步伐很好地配合,必然会有相当大的延迟。

恕我直言,没有一种方法可以解决问题。解决方案是研究可能性,然后通过反复试验找到最适合您的特定需求的方法。每个用户必须确定什么对他们的系统有效,而不是使用千篇一律的方法。

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

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

于 2016-05-23T23:30:29.607 回答
4

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

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

于 2009-01-21T19:13:05.670 回答
4

我遇到了类似的问题。我试图访问一个包含超过 10,000 个文件的目录。构建文件列表并在任何文件上运行任何类型的命令所花费的时间太长。

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

以下是我为解决该问题而编写的 php 脚本。

列出目录中的文件,其中包含太多用于 FTP 的文件

它如何帮助某人

于 2010-11-26T15:37:53.553 回答
3

我尊重这并不能完全回答你关于多少太多的问题,但解决长期问题的一个想法是,除了存储原始文件元数据之外,还要存储它存储在磁盘上的哪个文件夹 - 规范化取出那段元数据。一旦文件夹超出了您对性能、美观或任何原因感到满意的某个限制,您只需创建第二个文件夹并开始将文件放在那里...

于 2009-01-21T20:49:25.790 回答
1

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

选择更合适的FS(文件系统)。因为从历史的角度来看,你所有的问题都足够明智,曾经成为 FS 几十年来发展的核心。我的意思是更现代的 FS 可以更好地支持您的问题。首先从FS列表中根据您的最终目的制作比较决策表。

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

我不确定是否可以工作,但如果您不提及一些实验,请在当前文件系统上尝试 AUFS。我猜它具有将多个文件夹模拟为单个虚拟文件夹的功能。

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

于 2013-12-17T05:37:05.120 回答
1

只要不超过操作系统的限制,没有一个数字是“太多”的。但是,无论操作系统如何,目录中的文件越多,访问任何单个文件所需的时间就越长,并且在大多数操作系统上,性能是非线性的,因此从 10,000 个文件中查找一个文件需要超过 10 倍的时间然后在 1,000 中找到一个文件。

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

于 2014-02-16T00:18:19.463 回答
-6

完美无瑕,

完美无瑕,

绝对完美:

(通用汽车 - RIP)

function ff () { 
    d=$1; f=$2; 
    p=$( echo $f |sed "s/$d.*//; s,\(.\),&/,g; s,/$,," ); 
    echo $p/$f ; 
    }


ff _D_   09748abcGHJ_D_my_tagged_doc.json

0/9/7/4/8/a/b/c/G/H/J/09748abcGHJ_D_my_tagged_doc.json


ff -   gadsf12-my_car.json 

g/a/d/s/f/1/2/gadsf12-my_car.json

还有这个

ff _D_   0123456_D_my_tagged_doc.json

0/1/2/3/4/5/6/0123456_D_my_tagged_doc.json



ff .._D_   0123456_D_my_tagged_doc.json

0/1/2/3/4/0123456_D_my_tagged_doc.json

请享用 !

于 2021-06-14T08:42:54.500 回答