Creating algorithm for File system structure for auto-incremented images

0 votes
asked Aug 23, 2010 by teddyk

I have nearly 1 million photos auto-incremented starting at "1".

So, I have the following:

1.jpg
2.jpg
3.jpg
4.jpg
5.jpg
....
1000000.jpg

Currently, I have all of these files in a single Ext4 linux directory.

As you can imagine, the filesystem is crazy slow.

Using PHP, how can I create an algorithm that divides up my images into a directory structure so that each directly has significantly less objects per directory.

For example:

1000/1.jpg
1000/2.jpg
1000/3.jpg
...
1000/999.jpg
1000/1000.jpg
2000/1001.jpg
2000/1002.jpg
2000/1003.jpg
2000/1999.jpg

How would I divide/modulus/implode/shift the image name (id) into a file structure like such above?

UPDATE:

Basically, I want to create a PHP function that does the following.

  • Only accept positive integers, not including 0.
  • For values 1-999, return 0
  • For values 1000-1999, return 1000
  • For values 10,000-10,999, return 10000
  • For values 25,000-25,999, return 25000

4 Answers

0 votes
answered Aug 23, 2010 by bill-karwin

When I've done things like this in the past, I create subdirectories from the rightmost digits, so that as they increment, they are added to all the directories more evenly:

4/3/1234.jpg
5/3/1235.jpg
6/3/1236.jpg
7/3/1237.jpg
8/3/1238.jpg

Re your comment:

how would I do that with PHP?

Here's an example function in PHP:

function NumToPath($n)
{
  $n = (int) $n;
  if ($n <= 0) {
    return false;
  }
  $n = str_pad($n, 7, "0", STR_PAD_LEFT);
  preg_match("/.*(\d)(\d)$/", $n, $matches);
  $path = $matches[2] . "/" . $matches[1] . "/" . $n . ".jpg";
  return $path;
}
0 votes
answered Aug 23, 2010 by rufinus

i guess you think far to complex. untested very basic way of doing this:

for($i=0;$i<1000000;$i++){
  if(file_exists($i.'.jpg'){
     $multi = floor($i/1000);
     $dir = ($multi <= 1) $dir = 1000 : $dir=$multi*1000;

     if(!is_dir($dir)){
        mk_dir($dir);
     }

     move($i.'.jpg',$dir.'/'.$i.'.jpg);
  }
}
0 votes
answered Aug 23, 2010 by dasprid

You should keep the current (incrementing) number in a meta-file, so that you can retrieve it very quickly. Everything else is pretty easy:

$directory = ceil($num / 1000) * 1000;
$filename  = $num . '.jpg';
$path      = $directory . '/' . $filename;
0 votes
answered Aug 23, 2010 by chris-mcfarland

Untested but should work. Certainly back up your stuff first or try it on just a small sample directory.

<?php
// specify your image directory, no trailing slash
$imagedir = 'your/path/to/images';

// loop through each jpg file in the image directory
foreach (glob($imagedir.'/*.jpg') as $file)
{
    // determine new folder name
    $newdir = floor(basename($file) / 1000) * 1000; 
    // ^ php will interpret the filename's number for the calculation
    // eg: ('999.jpg' / 1000) returns .999

     // ensure the 0 folder name is not null
    if (!$newdir) {
        $newdir = '0';
    }

    // add the new folder to the image directory
    $newdir = $imagedir.'/'.$newdir; 
    if (!is_dir($newdir)) {
        mkdir($newdir);
    }

    // move the image
    rename($file, $newdir.'/'.basename($file);
}
?>
Welcome to Q&A, where you can ask questions and receive answers from other members of the community.
Website Online Counter

...