Как лучше всего присваивать имена загруженным изображениям?

15

Предположим, у меня есть форма в моем веб-приложении, где пользователи могут загрузить изображение профиля.

У меня мало требований к размеру файла, размерам и т. Д., Но когда пользователь загружает изображение, как мне их назвать в моей системе? Я предполагаю, что это должно быть последовательным и также уникальным.

Может быть, GUID?

a5c627bedc3c44b7ae7c06a44fb3fcf8.jpg

Отметка времени?

129899740140465735.jpg

Хэш? Пример: MD5

b1a9acaf295cf14ffbc5b6538294562c.jpg

Есть ли стандартный или рекомендуемый способ сделать это?

Роуэн Фриман
источник
7
Если ваша цель - сохранить только одну фотографию профиля для каждого пользователя, некоторые скажут, что очевидным выбором будет имя файла, совпадающее с идентификатором пользователя.
Алан Барбер
временная метка не очень хорошая идея, потому что DateTime.Now обновляется только каждые 15 мс. Существует высокая вероятность столкновения, например, во время массовой загрузки, запросов в очереди и т. Д.
jhexp

Ответы:

27

Вы должны попытаться достичь двух целей: уникальность и полезность.

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

Мое типичное решение состоит в том, чтобы вставить важную информацию в имя файла, такую ​​как идентификатор пользователя (если он принадлежит пользователю) или дата и время загрузки (если это важно), или имя файла, использованное при загрузке.

Это может действительно спасти ваш скин в один прекрасный день, когда информация, содержащаяся в имени файла, позволяет вам, например, восстановить ошибку или случайное удаление записей. Если все, что у вас есть, это GUID, и вы потеряете каталог, у вас будет куча работы по его очистке.

Например, если файл «My Holiday: Florida 23.jpg» загружен пользователем ID 98765 2013/04/04 в 12:51:23, я бы назвал его примерно так, добавив случайную строку ad8a7dsf9:

20130404125123-ad8a7dsf9-98765-мой-праздник-флорида-23.jpg

  • Уникальность обеспечивается датой и временем, а также случайной строкой (при условии, что она правильно выбрана из / dev / urandom или CryptGenRandom.
  • Если файл когда-либо отсоединен, вы можете указать пользователя, дату и время, а также заголовок.
  • Все сворачивается в нижний регистр, и все не алфавитно-цифровые удаляются и заменяются штрихами, что облегчает обработку имени файла с помощью простых инструментов (например, без пробелов, которые могут запутать плохо написанные скрипты, без двоеточий или других символов, которые запрещены в некоторых файловых системах). , и так далее).
Бен
источник
7
Для удобства я бы рекомендовал создавать отдельные каталоги для каждого идентификатора пользователя, чтобы при удалении пользователя вам не приходилось искать все его изображения. - так98765/20130404125123-ad8a7dsf9-my-holiday-florida-23.jpg
Шадур
1
Теоретически уникальность не обеспечивается случайной строкой.
Колюня
4
@Kolyuny, это правда, в том смысле, что гарантированная глобальная уникальность не является свойством, которое даже GUID имеет в реальной жизни (даже направляющие v1 отключаются из-за выдачи дублирующих MAC-адресов). Все, что вы можете получить, это статистическая вероятность уникальности. Но вы можете гарантировать уникальность, проверив, существует ли файл уже (атомарно используя CreateFilewith CREATE_NEW), и используя другую случайность, если это так.
Бен
«Все сворачивается в нижний регистр, и все не алфавитно-цифровые символы удаляются и заменяются черточками», я бы оставил это в смешанном регистре, удалил все не буквенно-цифровые
символы
4

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

Если вы планируете хранить тысячи файлов, я предлагаю разделить на папки. Например upload\silo001, upload\silo002и т. Д. Вы можете либо сбалансировать свои файлы, либо подождать, пока одна папка достигнет определенного количества файлов, а затем создать другую.

Что касается именования, я всегда называю файл с GUID, потому что он глобально уникален. Я вытягиваю расширение из загрузки и устанавливаю расширение файла для соответствия, но фактическое имя задается из нового Guid.

Если вы делаете это в сочетании с СУБД и имеют несколько категорий, то есть продукты, категории и т.д. , вы могли бы upload\products, upload\categoriesи так далее, и вы могли бы использовать идентификатор строки в качестве имени файла.

Что касается лучших практик, я тоже заглянул в прошлое и ничего не нашел. Я придумал вышеупомянутое, обсуждая с некоторыми из моих разработчиков.

Сэм
источник
2

В одном из решений, над которым я работал несколько лет назад, мы сделали это: подпапки для части идентификатора пользователя, поэтому, если ваш идентификатор пользователя был 232950192

у нас будут подпапки images / 23/29/50/192/232950192

в последней папке есть папки для albuns и imgs профиля и т. д.

Но мы также сохраняем все в базе данных и сохраняем ее в файловой системе для быстрого доступа к веб-серверу (который также имеет кеширование)

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

Очень легко создать подпапку в java и создать в ней файл:

    File folder = new File(pathwithslashes);// like "images/23/29/50/192/232950192"
    folder.mkdirs();
    File imgFile = new File(folder, name);
    //Now get output stream etc

Чтобы получить отметку даты в подпапках: SimpleDateFormat sdf = new SimpleDateFormat ("/ yyyy / MM / dd /"); pathwithslashes = pathwithslashes + sdf.format (now); // теперь является папкой util.Date File = new File (pathwithslashes);

Dot net /programming/5482230/c-sharp-equivalent-of-javas-mkdirs

мин tgkprog
источник
+1 за предложение вложенных каталогов. Я думаю, что это важно учитывать, поскольку разные файловые системы могут сталкиваться с проблемами производительности, когда папки содержат «слишком много» файлов: stackoverflow.com/questions/197162/… , support.microsoft.com/kb/130694/en-us и т. Д.
Деизель
1
да, в другой системе было одно из зависаний веб-сервера, когда мы пытались запустить rmdir в каталоге, содержащем более 400 000 файлов. у нас было больше таких папок. поэтому затем использовал пользовательскую программу, которая называется dir / p, чтобы получить несколько файлов для удаления одновременно. заняло несколько часов, но без простоя :)
tgkprog
1

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

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

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

Имейте в виду, что в настоящее время, когда доминируют мобильные интерфейсы, реальное имя файла является менее важной вещью, чем это было 5, 10 лет назад. Но даже если это будет иметь решающее значение в контексте вашего приложения, вы всегда можете задействовать некоторую магию старой школы с использованием Content-Disposition: attachment; filename="pretty_file_name.jpg"заголовка HTTP, создавая любое подходящее имя файла, которое вы пожелаете. Кроме того, современные браузеры прокладывают путь к новому HTML5-атрибуту загрузки . Я не верю, что на самом деле видеть «читабельное» имя изображения - это то, о чем вы должны думать в большинстве случаев.

UPD: можно внести изменения, чтобы в одном каталоге не было слишком много файлов - достаточно взять первые 3 буквы и создать каталог.

shabunc
источник
1
хотя md5 действительно уникален?
I.devries
@ I.devries, я не специалист, но, насколько я знаю, для этого достаточно. Особенно, если вы дополнительно проверите размер файла, поскольку хороший алгоритм хеширования фактически допускает, что у объектов одинакового размера будет меньше вероятности столкновения - stackoverflow.com/questions/2442632/…
shabunc
-1

Вероятность столкновения с чем-то вроде sha4 бесконечно мала. Если вы объедините хэш с идентификатором пользователя или даже с простой датой, тем более.

Эван Замир
источник