【问题标题】:Thousands of images, how should I organize the directory structure? (linux)上千张图片,我应该如何组织目录结构? (Linux)
【发布时间】:2012-08-01 00:32:38
【问题描述】:

我在由 1and1.com 托管的 Linux 服务器上收到成千上万用户上传的数千张图片(我相信他们使用 CentOS,但不确定版本)。这是一个与语言无关的问题,但是,供您参考,我使用的是 PHP。

我的第一个想法是将它们全部转储到同一个目录中,但是,我记得不久前,一个目录中可以放置多少个文件或目录是有限制的。

我的第二个想法是根据用户的电子邮件地址对目录内的文件进行分区(因为无论如何我都使用它作为用户名),但我不想遇到目录中目录的限制。 ...

无论如何,对于来自 user@domain.com 的图像,我打算这样做:

/images/domain.com/user/images...

这样做很聪明吗,如果成千上万的用户都说“gmail”,也许我可以更深入,像这样

/images/domain.com/[first letter of user name]/user/images...

所以对于 mike@gmail.com 来说应该是...

/images/domain.com/m/mike/images...

这是一个不好的方法吗?其他人都在做什么?我也不想遇到太多目录的问题...


相关:

【问题讨论】:

  • 我很确定还有另一个(更密切)相关的问题,但我没有找到它......
  • 当然有几个“数据库或文件系统”类型的问题。

标签: linux directory-structure


【解决方案1】:

我用于另一个要求但可以满足您需要的是使用简单的约定。

加1,得到新号码的长度,然后加上这个号码的前缀。

例如:

假设 'a' 是一个用最后一个 id 设置的 var。

a = 564;
++a;
prefix = length(a);
id = prefix + a; // 3565

然后,您可以使用此约定为目录使用时间戳:

20092305 (yyyymmdd)

然后你可以像这样爆炸你的路径:

2009/23/05/3565.jpg

(或更多)

这很有趣,因为您可以同时按日期和数字进行排序(有时很有用) 而且你仍然可以在更多目录中分解你的路径

【讨论】:

    【解决方案2】:

    我会做以下事情:

    1. 获取每个图像的 MD5 哈希值。
    2. 将 MD5 哈希写入您要跟踪这些内容的数据库中。
    3. 将它们存储在一个目录结构中,您可以在其中使用 MD5 哈希十六进制字符串的前几个字节作为目录名称。因此,如果哈希为 'abcdef1234567890',您将其存储为 'a/b/abcdef1234567890'。

    使用哈希还可以让您合并多次上传的同一张图片。

    【讨论】:

    • 几个 cmets:1) 用一个已知的值加盐你的哈希值。 2)“树平衡”散列到文件夹结构中。因此,取散列的前(比如说)五个字符并将其设为文件夹,然后是接下来的五个,依此类推。因此,任何给定文件夹中的文件夹都不会超过 100,000 个。以这种方式使用文件夹结构中的整个哈希。
    • @SteveMidgley 你能告诉我更多关于“树平衡”的信息吗?您是如何计算出任何给定文件夹中的文件夹不会超过 100,000 个的?
    • 树平衡结构 (en.wikipedia.org/wiki/B-tree) 意味着结构的每一层都有相等的部分。余额的大小应基于您的系统在任何给定级别可以处理的元素数量(一个文件夹中允许多少个文件夹+文件?)与您的系统可以处理的深度级别(子系统可以处理多少级别) -folders 是否适合您的设计?)。
    • @IstiakTridip - 所以你的算法会将哈希值分成相等的部分,第一部分(比如 4 位数字)将是一个文件夹,然后下一部分将是一个子文件夹,重复,直到你没有哈希字符串。您使用的哈希大小将由上述针对您的应用程序/系统/操作系统的宽度/深度问题决定。
    • @SteveMidgley 16 ^ 5 是 100 万……可能是 3 或 4 个分支最大
    【解决方案3】:

    扩展 Joe Beda 的方法:

    • 数据库
    • 数据库
    • 数据库

    如果您关心按用户、原始文件名、上传日期、拍照日期 (EXIF) 等对文件进行分组或查找,请将此元数据存储在数据库中并使用适当的查询来挑选适当的文件.

    使用数据库主键——无论是文件哈希还是自动递增数字——在一组固定的目录中定位文件(或者,使用每个目录的固定最大文件数 N,当你填满时)转到下一张,例如第 k 张照片应存储在 {somepath}/aaaaaa/bbbb.jpg 其中 aaaaaa = floor(k/N),格式为十进制或十六进制,bbbb = mod(k,N) , 格式为十进制或十六进制。如果层次结构对您来说太平,请使用 {somepath}/aa/bb/cc/dd/ee.jpg)

    不要将目录结构直接暴露给您的用户。如果他们使用 Web 浏览器通过 HTTP 访问您的服务器,请给他们一个类似 www.myserver.com/images/{primary key} 的 URL,并在 Content-Type 标头中编码正确的文件类型。

    【讨论】:

    • 所有图片都会在web文件夹的根目录下,所以如果不使用我们的函数检索它们就无法访问它们。
    • 仍然,如果您创建他们访问它们的结构,再加上您存储它们的结构,那么您将无法更改 URL。如果解耦了,以后必要时可以更改存储结构。
    【解决方案4】:

    这是我不久前针对这种情况编写的两个函数。它们已经在一个拥有数千名成员的网站上使用了一年多,每个成员都有很多文件。

    本质上,这个想法是使用每个成员的唯一数据库ID的最后一位来计算一个目录结构,为每个人提供一个唯一的目录。使用最后一个数字,而不是第一个数字,可确保目录分布更均匀。每个成员都有一个单独的目录意味着维护任务要简单得多,而且你可以看到人们的东西在哪里(就像视觉上一样)。

    // checks for member-directories & creates them if required
    function member_dirs($user_id) {
    
        $user_id = sanitize_var($user_id);
    
        $last_pos = strlen($user_id);
        $dir_1_pos = $last_pos - 1;
        $dir_2_pos = $last_pos - 2;
        $dir_3_pos = $last_pos - 3;
    
        $dir_1 = substr($user_id, $dir_1_pos, $last_pos);
        $dir_2 = substr($user_id, $dir_2_pos, $last_pos);
        $dir_3 = substr($user_id, $dir_3_pos, $last_pos);
    
        $user_dir[0] = $GLOBALS['site_path'] . "files/members/" . $dir_1 . "/";
        $user_dir[1] = $user_dir[0] . $dir_2 . "/";
        $user_dir[2] = $user_dir[1] . $dir_3 . "/";
        $user_dir[3] = $user_dir[2] . $user_id . "/";
        $user_dir[4] = $user_dir[3] . "sml/";
        $user_dir[5] = $user_dir[3] . "lrg/";
    
        foreach ($user_dir as $this_dir) {
            if (!is_dir($this_dir)) { // directory doesn't exist
                if (!mkdir($this_dir, 0777)) { // attempt to make it with read, write, execute permissions
                    return false; // bug out if it can't be created
                }
            }
        }
    
        // if we've got to here all directories exist or have been created so all good
        return true;
    
    }
    
    // accompanying function to above
    function make_path_from_id($user_id) {
    
        $user_id = sanitize_var($user_id);
    
        $last_pos = strlen($user_id);
        $dir_1_pos = $last_pos - 1;
        $dir_2_pos = $last_pos - 2;
        $dir_3_pos = $last_pos - 3;
    
        $dir_1 = substr($user_id, $dir_1_pos, $last_pos);
        $dir_2 = substr($user_id, $dir_2_pos, $last_pos);
        $dir_3 = substr($user_id, $dir_3_pos, $last_pos);
    
        $user_path = "files/members/" . $dir_1 . "/" . $dir_2 . "/" . $dir_3 . "/" . $user_id . "/";
        return $user_path;
    
    }
    

    sanitize_var() 是用于清理输入并确保其为数字的支持函数,$GLOBALS['site_path'] 是服务器的绝对路径。希望它们能不言自明。

    【讨论】:

      【解决方案5】:

      Joe Beda 的回答几乎是完美的,但请注意,MD5 已被证明在笔记本电脑上 iirc 2 小时内可碰撞?

      也就是说,如果您真的以上述方式使用文件的 MD5 哈希,您的服务将容易受到攻击。攻击会是什么样子?

      1. 黑客不喜欢某张照片
      2. 他确保这是您正在使用的普通 MD5(image+secret_string 的 MD5 会吓跑他)
      3. 他使用了一种神奇的方法,将一张(在这里发挥你的想象力)哈希的图片与他不喜欢的照片相撞
      4. 他像往常一样上传照片
      5. 您的服务会用新服务覆盖旧服务并同时显示两者

      有人说:那我们不要覆盖它。然后,如果可以预测某人会上传某些东西(例如,网络上的热门图片可能会被上传),则可以先获取它的“散列位置”。用户在上传小猫的图片时会很高兴,他会发现它实际上看起来像(在这里发挥你的想象力)。 我说:使用 SHA1,因为它在 iirc 127 年内被 10.000 台计算机集群证明是可破解的?

      【讨论】:

      • 你说的是原像攻击,它还没有成功针对 MD5,只有碰撞攻击vpnc.org/hash.html
      • en.wikipedia.org/wiki/MD5 : "2005 年 3 月 1 日,Arjen Lenstra、Xiaoyun Wang 和 Benne de Weger 演示了使用不同的公钥和相同的 MD5 哈希构造两个 X.509 证书,这是一个明显实际的碰撞。” (...)
      【解决方案6】:

      在这方面可能会迟到。但是一种解决方案(如果它适合您的用例)可能是文件名散列。这是一种使用文件名创建易于重现的文件路径的方法,同时还创建了一个分布良好的目录结构。例如,您可以使用文件名哈希码的字节作为其路径:

      String fileName = "cat.gif";
      int hash = fileName.hashCode();
      int mask = 255;
      int firstDir = hash & mask;
      int secondDir = (hash >> 8) & mask;
      

      这将导致路径为:

      /172/029/cat.gif
      

      然后您可以通过重现算法在目录结构中找到cat.gif

      使用 HEX 作为目录名称就像转换 int 值一样简单:

      String path = new StringBuilder(File.separator)
              .append(String.format("%02x", firstDir))
              .append(File.separator)
              .append(String.format("%02x", secondDir)
              .toString();
      

      导致:

      /AC/1D/cat.gif
      

      几年前我写了一篇关于这个的文章,最近把它移到了 Medium。它有更多细节和一些示例代码:File Name Hashing: Creating a Hashed Directory Structure。希望这会有所帮助!

      【讨论】:

        猜你喜欢
        • 2011-10-24
        • 2019-02-06
        • 1970-01-01
        • 2017-08-18
        • 2013-10-04
        • 2011-10-23
        • 2023-04-07
        • 1970-01-01
        相关资源
        最近更新 更多