-1

アーカイブされたファイルがアップロードされて保存されるサーバーがあります。ファイルの存在の一覧表示とチェックのパフォーマンスを向上させるために、パフォーマンス指向のディレクトリ構造でファイルを編成する必要があります。

ファイルの実際の名前と一時名を保持するデータベース テーブルがあります。

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

ルート ディレクトリには、0 ~ 999 の範囲の最大 1000 個のサブディレクトリを含めることができます。各ディレクトリには 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 番目のファイルがアップロードされたときに発生し、ファイルを 2 番目のレベルに保存する必要があります。

0 番目のディレクトリ root/0/0 - root/0/999 に 0 - 999 の範囲の第 2 レベルのディレクトリを作成する必要があります。

次に、root/0/999 に到達し、そこに 1000 個のファイルを配置したら、root/999/999 に到達するまで、root/1/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 個のディレクトリ/ファイルを作成できます。(もちろん、別の分割長を選択すると、これは異なります)

ディレクトリを簡単に作成するには、mkdirの 3 番目のパラメーターを使用できます。

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

そうすれば、10 ではなく 1 の後に 2 が来るようになります。

シンプルで効果的。

追加: 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つまり、ターゲット アドレス空間に均等に分散できるように、整数 ( ) をハッシュ (またはその他の方法で精巧) にする必要があります。

1 つの方法は、採用している方法です。最大で 1,000 億のレコードを保持したいとします。したがって、管理する最大数は 999,999,999,999 または 4 レベルです。

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*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);
}

getPath09dの代わりに必要になることを除いて、同じままです012d。サイズ 3 の 2 レベルに制限する場合は、さらに に減らし06dます。

于 2012-08-30T09:43:16.337 に答える