命名上传图像的最佳做法是什么?


15

假设我的Web应用程序中有一个表单,用户可以在其中上传个人资料图片。

我对文件大小,尺寸等几乎没有要求,但是当用户上传图像时,如何在系统上命名它们?我想它需要保持一致并且也是唯一的。

也许是GUID?

a5c627bedc3c44b7ae7c06a44fb3fcf8.jpg

时间戳记?

129899740140465735.jpg

哈希?例如:md5

b1a9acaf295cf14ffbc5b6538294562c.jpg

有没有标准或推荐的方法来做到这一点?


7
如果您的目标是每位用户仅存储一张个人资料图片,则有人会说显而易见的选择是将文件命名为与用户ID相同。
艾伦·巴伯

时间戳不是一个好主意,因为DateTime.Now仅每15毫秒刷新一次。有碰撞的机会很高,例如在的bulkload,排队的请求等。
jhexp

Answers:


27

您应该尝试实现两个目标:唯一性和有用性。

使用GUID可以保证唯一性,但是有一天,文件可能会从其原始来源中分离出来,然后会遇到麻烦。

我的典型解决方案是将关键信息嵌入文件名中,例如userID(如果它属于用户)或上载的日期和时间(如果这很重要),或者上载时使用的文件名。

当文件名中嵌入的信息使您能够(例如)从错误中恢复或意外删除记录时,这可能真的可以节省一天的时间。如果您只有GUID,并且丢失了目录,则将很难完成此工作。

例如,如果用户ID 98765在2013/04/04的12:51:23上载了“我的假期:佛罗里达23.jpg”文件,则我将这样命名,并添加一个随机字符串ad8a7dsf9

20130404125123-ad8a7dsf9-98765-my-holiday-florida-23.jpg

  • 日期和时间以及随机字符串可确保唯一性(前提是该字符串可以从/ dev / urandom或CryptGenRandom中正确随机获得)。
  • 如果文件曾经分离过,则可以标识用户,日期和时间以及标题。
  • 一切都折叠成小写,任何非字母数字都被删除并用破折号代替,这使得文件名易于使用简单的工具处理(例如,没有空格可能会使书写不良的脚本迷惑,没有冒号或某些文件系统上禁止的其他字符) , 等等)。

7
为了整理房间,我建议为每个用户ID创建单独的目录,这样,如果您删除某个用户,则不必四处寻找所有图片。-所以98765/20130404125123-ad8a7dsf9-my-holiday-florida-23.jpg
Shadur

1
理论上,唯一性不是随机字符串提供的。
Kolyunya

4
@Kolyuny,的确如此,从某种意义上说,保证全球唯一性甚至不是GUID在现实生活中拥有的属性(由于发布了重复的MAC地址,即使v1 guid也被破坏了)。您所能获得的是唯一性的统计可能性。但是,您可以通过检查文件是否已经存在来确保唯一性(在原子上使用CreateFileCREATE_NEW),如果存在则使用不同的随机性。

“将所有内容折叠成小写,将所有非字母数字都删除并替换为破折号,”我将保留大小写混合,删除所有非字母数字并用分数代替,最后一个破折号除外
tgkprog

4

您不希望对应用程序(例如Explorer)施加压力,并在打开目录时使其崩溃。虽然不太可能要强调实际的文件系统,但是如果要存储成千上万个文件,则需要考虑到这一点。

如果您希望存储数千个文件,我的建议是将其分区到文件夹中。例如upload\silo001upload\silo002等。您可以平衡文件,也可以等到文件夹命中一定数量的文件然后再创建一个。

关于命名,我总是使用GUID命名文件,因为它是全局唯一的。我确实从上传中提取了扩展名,并将文件的扩展名设置为匹配,但是实际名称是从新的Guid设置的。

如果与RDBMS一起执行此操作,并且具有多个类别(即产品,类别等),则可以具有upload\productsupload\categories等等,并且可以将行ID用作文件名。

在最佳实践方面,我过去也没有发现任何东西。在与一些开发人员讨论时,我想到了以上内容。


2

在几年前我尝试的一种解决方案中,我们执行了以下操作:部分用户ID的子文件夹,因此,如果您的用户ID为232950192

我们将有子文件夹images / 23/29/50/192/232950192

在最终文件夹中,有用于相册和个人资料imgs的文件夹

但是我们也将所有内容保存在数据库中,并将其保留在文件系统中,以便快速访问Web服务器(也具有缓存)

无论如何,最终图像将具有原始图像名称。我们不需要保留版本。但是,在最终专辑名称下或在数据库中使用版本ID可以保留更多子文件夹的原因。需要思考一下,一旦投入生产,就很难在没有时间和不容易纠正当前结构的情况下更改事物

在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);

点网/programming/5482230/c-sharp-equivalent-of-javas-mkdirs


+1用于建议嵌套目录。我认为要考虑为不同的文件系统可能会遇到性能问题时,文件夹中包含“太多”的文件,这是很重要的:stackoverflow.com/questions/197162/...support.microsoft.com/kb/130694/en-us
deizel

1
是的,在另一个系统上,当我们尝试在具有超过40万个文件的dir上rmdir时,Web服务器挂起了一个。我们有更多这样的文件夹。因此,然后使用了一个名为dir / p的自定义程序来一次删除几个文件。花了几个小时,但没有停机时间:)
tgkprog

1

我建议只使用md5或任何概念上等效的东西。通过按内容摘要重命名文件,您不仅在授予唯一性(总是尽可能长地缓存图像,而且基于内容的重命名,再加上适当的重命名,实际上可以永远缓存图像)。

同样,这没什么大不了的,但是当不同的用户上传完全相同的图像时,这并不是一个纯粹的假设情况。开箱即用,您将进行小的数据存储优化。

至于其他建议:至于我,我坚决反对在文件名中保留任何类型的辅助信息。当我还年轻(也更苗条:)时,我一直是Perl开发人员,并且习惯于以常识允许的方式在文件名中存储尽可能多的辅助信息,因为Perl字符串模式功能很棒。我得出的结论是,谈到Web开发,始终将与文件关联的数据与文件名分开保存始终是更好的选择。

请记住,如今,在移动接口占主导地位的情况下,实际文件名已比10年前的5变得不那么重要了。但是,即使这对于您的应用程序而言至关重要,但您始终可以通过使用Content-Disposition: attachment; filename="pretty_file_name.jpg"HTTP标头来构造一些老式的魔术,从而构造所需的任何相关文件名。另外,现代浏览器正在为新的HTML5属性(下载)铺平道路。我不认为实际上看到“人类可读”的图像名称是大多数情况下您应该考虑的事情。

UPD:可以进行修改,以使一个目录中没有太多文件-只需输入前3个字母并创建dir。


1
md5真的很独特吗?
I.devries

@ I.devries,我不是专家,但据我所知,足够用于此目的。特别是如果你还检查文件的大小,因为好的哈希算法实际授予同样大小的实体将不太可能有一个碰撞- stackoverflow.com/questions/2442632/...
shabunc

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.