-1

我有一个服务器,存档文件将被上传和存储。为了提高列出和检查文件存在性的性能,我需要将文件组织在面向性能的目录结构中。

我有一个数据库表,它将保存文件的真实名称及其临时名称。

###################################
FILES
###################################
id int auto_increment primary key,
name varchar (255),
temp_name varchar (255)

根目录最多可以包含 1000 个子目录,范围从 0-999。每个目录将包含 1000 个文件。

所以结果将是

root/0 ==> will hold file having the id range from 1-999
root/1 ==> will hold file having the id range from 1000-1999
root/2 ==> will hold file having the id range from 2000-1999
.
.
.
root/999 ==> will hold file having the id range from 999,000-999,999

可以使用以下等式找到存储文件的目录

$directory = floor($file_id_from_db/1000);

WHERE $file_id_from_db 从文件数据库表中检索filesid.

当第 1,000,000 个文件被上传时会出现问题,然后我必须开始将文件存储在第二级。

我必须在第 0 个目录 root/0/0 - root/0/999 中创建第二级目录,范围从 0 - 999

然后当我到达 root/0/999 并且我已经在其中放置了 1000 个文件时,我需要移动到 root/1/999 等等,直到我到达 root/999/999。

我当前的功能看起来像这样

function getPath($id){    
     $result = floor($file_id/1000);
     //Second level checks (Tried and crashed and burned)
     return "/$result"; 
}

我不知道如何实现创建子目录的逻辑?

感谢您的任何建议。

4

4 回答 4

3

如果可以使用其他方法,您可以尝试以下方法:

  • 将 db-id 填充到例如 20 个位置(从长远来看就足够了),例如:00000000000001665765
  • 将该字符串拆分为适合长度的块(例如 2),然后使用您的 DIRECTORY_SEPARATOR 重新加入这些块

这将是您的存储路径,例如:

$id = 1665765;
$paddedId = str_pad($id, 20, '0', STR_PAD_LEFT);

echo $path = '/' . implode(DIRECTORY_SEPARATOR, str_split($paddedId, 2));

// ==> /00/00/00/00/00/00/01/66/57/65

这样,每个目录最多有 100 个目录/文件。(如果您选择另一个split-length,这当然会有所不同)

要轻松创建目录,您可以使用mkdir的第三个参数。

mkdir(dirname($path), 0755, true);
于 2012-08-30T09:40:47.647 回答
1

我正在使用它并且像魅力一样工作。

$dir = str_pad(substr( ($file_id + 1000), 0, (strlen(($file_id + 1000)) - 3)), 5, "0", STR_PAD_LEFT);

所有文件夹都有 5 个数字,如下所示:00001

这样,它将确保 2 在 1 而不是 10 之后,依此类推。

简单有效。

补充:如果你想从 0 开始,不要像这样使用它。(注意 -1)

$dir = str_pad(substr( ($file_id + 1000), 0, (strlen(($file_id + 1000)) - 3)) - 1, 5, "0", STR_PAD_LEFT);

另一个补充:我想我得到了你想要的东西。

试试这个:一旦达到 100 万,它将在现有文件夹中添加子文件夹。

$dir = str_pad(substr( ($file_id + 1000), 0, (strlen(($file_id + 1000)) - 3)) - 1, 4, "0", STR_PAD_LEFT);
if($dir > 1000) { $dir = str_pad(substr($dir, 0, strlen($dir) - 3), 4, "0", STR_PAD_RIGHT) . DIRECTORY_SEPARATOR . str_pad(substr($dir, -3) - 1, 4, "0", STR_PAD_LEFT); }
于 2012-08-30T09:46:32.520 回答
1

这个功能可能更适合你吗?

function getPath($id)
{
    if ($id < 100) return "0".DIRECTORY_SEPARATOR;
    $id = str_pad($id,strlen($id)+(3-strlen($id)%3),"0",STR_PAD_LEFT);
    $in = array_map(create_function('$x','return ($x >= 1) ? ltrim($x,\'0\') : "0";'),str_split($id,3));
    array_pop($in);
    $in = array_reverse($in);
    return rtrim(implode(DIRECTORY_SEPARATOR,$in),DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR;
}

测试板:http ://codepad.org/alRDCWlU

于 2012-08-30T10:00:02.767 回答
0

换句话说,您需要散列(或以其他方式详细说明)一个整数 ( id),以便它可以均匀地分布在目标地址空间上。

一种方法是您正在采用的方法。假设您最多要保存一千亿条记录,因此您管理的最大数量是 999,999,999,999 或四个级别。

function storeFile($id, $source_path)
{
    GLOBAL $BASE_PATH;
    $seq = sprintf("%012d", $id); // Transforms 42 in 000000000042

    $dir = str_split($seq, 3);  // Transforms in { 000 000 000 042 }

    $file = array_pop($dir);    // Get 042 which is the file name

创建后,如果需要,我们需要创建中间目录编辑:实际上@Yoshi 的解决方案要好得多)

    // Now build directory

    $path = $BASE_PATH;
    foreach($dir as $component)
    {
        $path .= "/$component";
        if (!is_dir($path))
            mkdir($path);
    }
    // The above can be replaced with mkdir(getPath($id), 0755, true); [@Yoshi]

    // Now $path exists and is /my/base/path/000/000/000

    // $path/$file is my file name, 042 in $path
    rename($source_path, $dest_path = "$path/$file");

    // Just to check. TRUE if everything was hunky dory; FALSE if something went bad.
    return file_exists($dest_path);

}

每次存储文件时,都运行上述程序并在需要时创建目录。

在恢复时,您可以运行

  function getPath($id)
  {
      GLOBAL $BASE_PATH;
      return $BASE_PATH . implode('/', str_split(sprintf("%012d", $id), 3));
  }

并直接获取文件名。

更新:'/' 是 Unix 路径分隔符(也应该在 Windows 下工作),但您可能希望将其替换为您平台的目录分隔符。

如果您想保留文件名(并不总是建议,因为它在用户的控制之下,国际字符可能与文件系统编码发生冲突,等等),您可以这样做。我们现在只需要三个级别,所以一个 3*3 的路径:

function storeFile($id, $source_path)
{
    GLOBAL $BASE_PATH;
    $seq = sprintf("%09d", $id); // Transforms 42 in 00000042

    $dir = str_split($seq, 3);  // Transforms in { 000 000 042 }

    // Now build directory. 042 is last directory

    $path = $BASE_PATH;
    foreach($dir as $component)
    {
        $path .= "/$component";
        if (!is_dir($path))
            mkdir($path);
    }

    // Use name component of source file
    $file = basename($source_path);

    // $path/$file is my file name, 042 in $path
    rename($source_path, $dest_path = "$path/$file");

    // Just to check. TRUE if everything was hunky dory; FALSE if something went bad.
    return file_exists($dest_path);
}

getPath保持不变,只是它现在需要09d而不是012d. 如果您想限制为大小 3 的两个级别,请进一步减小到06d.

于 2012-08-30T09:43:16.337 回答