我有一台服务器,可以上传和存储存档文件。为了提高列表和检查文件存在的性能,我需要在面向性能的目录结构中组织文件。
我有一个数据库表,它将保存文件的真实名称及其临时名称。
###################################
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从文件数据库表files
中恢复。id
。
问题发生在第1,000,000个文件被上传时,我必须开始将文件存储在第二级。
我必须在第0个目录中创建第二级目录,范围从0到999 root / 0/0 - root / 0/999
然后当我到达root / 0/999并且我已经放入了1000个文件时,我需要移动到 root / 1/9999等等,直到我达到root / 999/999。
我当前的功能看起来像那样
function getPath($id){
$result = floor($file_id/1000);
//Second level checks (Tried and crashed and burned)
return "/$result";
}
我不知道如何实现创建子目录的逻辑?
感谢您的任何建议。
答案 0 :(得分:3)
如果可以采用其他方法,您可以尝试以下方法:
00000000000001665765
这将是您的存储路径,例如:
$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个目录/文件。 (如果你选择另一个分裂长度),这当然会有所不同
要轻松创建目录,您可以使用mkdir的第三个参数。
mkdir(dirname($path), 0755, true);
答案 1 :(得分: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); }
答案 2 :(得分: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;
}
答案 3 :(得分: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));
}
并直接获取文件名。
UPDATE :'/'是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
。