Тысячи изображений, как мне организовать структуру каталогов? (Linux)
Я получаю тысячи фотографий, загруженных тысячами пользователей на моем Linux-сервере, который размещен на сайте 1and1.com(я считаю, что они используют CentOS, но я не уверен в этой версии). Это вопрос агностики языка, однако для вашей справки я использую PHP.
Моя первая мысль заключалась в том, чтобы просто сбросить их все в одном каталоге, однако, я помню, что некоторое время назад было ограничение количества файлов или каталогов в каталоге.
Моя вторая мысль заключалась в разделении файлов внутри каталогов на основе адреса электронной почты пользователей (поскольку это то, что я использую для имени пользователя в любом случае), но я не хочу ограничивать каталоги в каталоге....
Во всяком случае, для изображений с [email protected], я собирался сделать это:
/images/domain.com/user/images...
Является ли это умным, что, если тысячи пользователей скажут "gmail", возможно, я мог бы пойти глубже, вроде этого
/images/domain.com/[first letter of user name]/user/images...
поэтому для [email protected] это будет...
/images/domain.com/m/mike/images...
Это плохой подход? Что делают все остальные? Я не хочу сталкиваться с проблемами со слишком большим количеством каталогов...
по теме:
Ответы
Ответ 1
Я бы сделал следующее:
- Возьмите хэш MD5 каждого изображения, когда оно появится.
- Напишите этот хэш MD5 в базе данных, где вы отслеживаете эти вещи.
- Сохраните их в структуре каталогов, где вы используете первую пару байтов шестнадцатеричной строки хеша MD5 в качестве имени dir. Поэтому, если хеш "abcdef1234567890", вы сохраните его как "a/b/abcdef1234567890".
Использование хэша также позволяет объединить один и тот же образ, загруженный несколько раз.
Ответ 2
чтобы расширить подход Джо Беды:
- базы данных
- базы данных
- базы данных
если вам нужна группировка или поиск файлов пользователем, исходное имя файла, дата загрузки, дата снятия фотографии (EXIF) и т.д., сохраняйте эти метаданные в базе данных и используйте соответствующие запросы для выбора соответствующих файлов.
Использовать первичный ключ базы данных — будь то хэш файла или автоинкрементный номер — для поиска файлов среди фиксированного набора каталогов (в качестве альтернативы используйте фиксированные максимальные номера файлов N для каждого каталога, а когда вы заполняете переход к следующему, например, k-я фотография должна храниться в {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/{primary key} и закодируйте правильный тип файла в заголовке Content-Type.
Ответ 3
То, что я использовал для другого требования, но которое может соответствовать вашим потребностям, заключается в использовании простого соглашения.
Приращение на 1 и получение длины нового номера, а затем префикс с этим номером.
Например:
Предположим, что 'a' - это var, который задается с последним id.
a = 564;
++a;
prefix = length(a);
id = prefix + a; // 3565
Затем вы можете использовать временную метку для каталога, используя это соглашение:
20092305 (yyyymmdd)
Затем вы можете взорвать свой путь следующим образом:
2009/23/05/3565.jpg
(или более)
Это интересно, потому что вы можете сохранить порядок сортировки по дате и по числу одновременно (иногда полезно)
И вы еще можете разложить свой путь в других каталогах
Ответ 4
Вот две функции, которые я написал некоторое время назад для этой ситуации. Они используются более года на сайте с тысячами членов, каждый из которых имеет множество файлов.
По сути, идея состоит в том, чтобы использовать последние цифры уникального идентификатора базы данных каждого участника, чтобы вычислить структуру каталогов с уникальным каталогом для всех. Использование последних цифр, а не первого, обеспечивает более равномерное распространение каталогов. Отдельный каталог для каждого члена означает, что задачи обслуживания намного проще, плюс вы можете видеть, где люди (как в визуальном виде).
// 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'] - это абсолютный путь для сервера. Надеюсь, в противном случае они будут понятны.
Ответ 5
Ответ на Joe Beda почти идеальный, но обратите внимание, что MD5 доказал, что он может быть убит в течение 2 часов на ноутбуке?
Тем не менее, если вы на самом деле будете использовать хэш файла MD5 описанным образом, ваш сервис станет уязвимым для атак. Как будет выглядеть атака?
- Хакеру не нравится конкретное фото
- Он гарантирует, что это простой MD5, который вы используете (MD5 изображения + secret_string может напугать его)
- Он использует волшебный метод столкновения картины (используйте ваше воображение здесь) хеш с фотографией, которую он не любит
- Он загружает фотографию, как обычно.
- Ваша служба перезаписывает старую новую и отображает оба
Кто-то говорит: пусть не перезаписывает его тогда. Затем, если можно предсказать, что кто-то выгрузит что-то (например, популярная картинка в Интернете может быть загружена), сначала можно взять "хэш-место". Пользователь был бы счастлив при загрузке изображения котенка, он обнаружил, что он на самом деле выглядит как (используйте свое воображение здесь).
Я говорю: используйте SHA1, поскольку было доказано, что он был взломан в течение 127 лет кластером в 10 000 компьютеров?
Ответ 6
Возможно, будет поздно в игре. Но одно решение (если оно подходит вашему прецеденту) может быть хэшированием имени файла. Это способ создания легко воспроизводимого пути к файлу с использованием имени файла, а также создания хорошо распределенной структуры каталогов. Например, вы можете использовать байты файла hashcode имени файла как его путь:
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. Он содержит несколько подробностей и пример кода: Хеширование имен файлов: создание хеш-структуры каталогов. Надеюсь, это поможет!