Тысячи изображений, как мне организовать структуру каталогов? (Linux) - PullRequest
10 голосов
/ 23 мая 2009

Я получаю тысячи фотографий, загруженных тысячами пользователей на мой сервер Linux, который размещен на 1and1.com (я думаю, что они используют 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...

Это плохой подход? Что все остальные делают? Я также не хочу сталкиваться с проблемами со слишком большим количеством каталогов ...


Связанный:

Ответы [ 6 ]

27 голосов
/ 23 мая 2009

Я бы сделал следующее:

  1. Возьмите MD5-хэш каждого изображения по мере его поступления.
  2. Запишите этот MD5-хэш в базу данных, где вы отслеживаете эти вещи.
  3. Сохраните их в структуре каталогов, где вы используете первые пару байтов шестнадцатеричной строки MD5 в качестве имени dir. Поэтому, если хеш имеет значение «abcdef1234567890», вы должны сохранить его как «a / b / abcdef1234567890».

Использование хэша также позволяет объединять одно и то же изображение, загруженное несколько раз.

4 голосов
/ 23 мая 2009

, чтобы расширить подход Джо Беды:

  • база
  • база
  • база

если вам нужно сгруппировать или найти файлы по пользователю, оригинальному имени файла, дате загрузки, дате фотографирования (EXIF) и т. Д., Сохраните эти метаданные в базе данных и используйте соответствующие запросы, чтобы выбрать подходящие файлы .

Использовать первичный ключ базы данных & mdash; хэш файла или автоинкрементный номер & mdash; чтобы найти файлы среди фиксированного набора каталогов (в качестве альтернативы, используйте фиксированное максимальное число файлов N на каталог, и при заполнении перейдите к следующему, например, k th фотография должна быть хранится в {somepath}/aaaaaa/bbbb.jpg, где aaaaaa = floor (k / N), отформатированный как десятичный или шестнадцатеричный, и bbbb = mod (k, N), отформатированный как десятичный или шестнадцатеричный. Если это слишком плоская иерархия для вас, используйте что-то вроде {somepath}/aa/bb/cc/dd/ee.jpg)

Не раскрывайте структуру каталогов непосредственно вашим пользователям. Если они используют веб-браузеры для доступа к вашему серверу через HTTP, дайте им URL-адрес, например www.myserver.com/images/ndomprimary key}, и закодируйте правильный тип файла в заголовке Content-Type.

3 голосов
/ 23 мая 2009

Вот две функции, которые я написал некоторое время назад именно для этой ситуации. Они были использованы более года на сайте с тысячами участников, у каждого из которых есть много файлов.

По сути, идея состоит в том, чтобы использовать последние цифры уникального идентификатора базы данных каждого члена для расчета структуры каталогов, с уникальным каталогом для всех. Использование последних цифр, а не первых, обеспечивает более равномерное распределение каталогов. Отдельный каталог для каждого участника означает, что задачи по обслуживанию намного проще, плюс вы можете видеть, где находятся люди (как в визуальном плане).

// 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'] - это абсолютный путь для сервера. Надеюсь, в противном случае они будут говорить сами за себя.

3 голосов
/ 23 мая 2009

То, что я использовал для другого требования, но которое может соответствовать вашим потребностям, - это использование простого соглашения.

Увеличьте на 1 и получите длину нового номера, а затем добавьте префикс к этому номеру.

Например:

Предположим, что 'a' - это переменная с последним идентификатором.

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

Затем вы можете использовать временную метку для каталога, используя это соглашение:

20092305 (yyyymmdd)

Тогда вы можете взорвать свой путь так:

2009/23/05/3565.jpg

(или больше)

Это интересно, потому что вы можете сохранять порядок сортировки по дате и по номеру одновременно (иногда полезно) И вы все еще можете разложить свой путь в другие каталоги

2 голосов
/ 23 мая 2009

Ответ Джо Беды почти идеален, но, пожалуйста, обратите внимание, что MD5 оказался совместимым в течение 2 часов на ноутбуке?

Тем не менее, если вы на самом деле будете использовать хеш файла MD5 описанным способом, ваша служба станет уязвимой для атак. Как будет выглядеть атака?

  1. Хакеру не нравится конкретная фотография
  2. Он гарантирует, что это обычный MD5, который Вы используете (MD5 изображения + secret_string может его напугать)
  3. Он использует магический метод сопоставления фотографии (используйте здесь свое воображение) хеша с фотографией, которая ему не нравится
  4. Он загружает фото, как обычно
  5. Ваш сервис перезаписывает старый на новый и отображает оба

Кто-то говорит: давайте тогда не будем переписывать это. Затем, если можно предсказать, что кто-то загрузит что-то (например, может быть загружено популярное изображение в сети), можно сначала занять его «хэш-место». Пользователь будет счастлив, загрузив изображение котенка, он обнаружит, что оно на самом деле выглядит так (используйте здесь свое воображение). Я говорю: использовать SHA1, так как он доказал возможность взлома в iirc 127 лет кластером из 10.000 компьютеров?

0 голосов
/ 25 июня 2017

Возможно, опоздаю к игре по этому вопросу. Но одним из решений (если оно соответствует вашему варианту использования) может быть хеширование имени файла. Это способ создать легко воспроизводимый путь к файлу, используя имя файла, а также создать хорошо распределенную структуру каталогов. Например, вы можете использовать байты хэш-кода имени файла в качестве пути:

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. В нем есть еще несколько деталей и пример кода: Хеширование имени файла: создание хешированной структуры каталогов . Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...