存储上载的图像,SQL数据库或磁盘文件系统的最佳位置是什么?


146

我正在编写一个允许用户将图像上传到服务器的应用程序。我希望每天约20张全jpeg图像,并且可能未编辑/调整大小。(这是另一个问题,如何在存储之前在服务器端调整图像大小。也许有人可以在注释中删除.NET资源)。我现在想知道存储上传图像的最佳位置是什么。

  • 将图像作为文件存储在文件系统中,并在具有该图像确切路径的表中创建记录。

  • 或者,使用数据库服务器的“图像”或“二进制数据”数据类型将图像本身存储在表中。

我看到了两者的优点和缺点。我喜欢a),因为我可以轻松地重定位文件,而只需更改表条目。另一方面,我不喜欢将业务数据存储在Web服务器上,并且我真的不希望将Web服务器连接到保存业务数据的任何其他数据源(出于安全原因),我喜欢b),因为所有信息都是在一个地方,并且可以通过查询轻松访问。另一方面,数据库很快就会变得很大。将数据外包可能会更加困难。


2
我没有找到它,在哪里?
Tobias


Answers:


95

我通常将文件存储在文件系统上,因为这是它的用途,尽管有例外。对于文件,文件系统(通常)是最灵活,性能最高的解决方案。

将文件存储在数据库中存在一些问题-文件通常比平均行大得多-包含许多大文件的结果集将占用大量内存。另外,如果您使用采用表锁进行写操作的存储引擎(例如,ISAM),则文件表可能经常被锁定,具体取决于存储在其中的文件的大小/速率。

关于安全性-我通常将文件存储在文档根目录之外的目录中(无法通过http请求访问),并通过脚本进行服务,该脚本首先检查正确的授权。


7
您能否以技术细节向我解释最后一段(关于安全性),否则任何指示都将非常有帮助。谢谢。
VishwaKumar 2012年

39
(对于所有在那里的Google员工)如果您将网站的根目录配置为“公用”文件夹(如my_website / public /而不是my_website /),则可以将图像与其余部分一起存储在my_website / my_images文件夹中您的应用。然后,您的img标签将引用“ my_website / image.php?img_id = 55”,而不是“ my_website / avatar.png”,并且您的image.php脚本在验证凭据并解析了您提供的ID后,将返回实际值。图片。这样,只有适当的登录用户才能查看该图像。
Captain Hypertext

8
嘿队长,你应该把它变成一个实际的答案,这样你就可以得到积分$$
Andrew

4
请在安全性/防止文件破坏销毁网站上添加更多说明
安德鲁(Andrew)

1
这样就不会扩展,文件夹中的文件数量是有限制的,如果您打算将文件划分为多个文件夹,那么它将增加索引文件的复杂性(以标识文件的实际存储位置)。而且,搜索将非常慢。
哈迪克

43

选项B的唯一好处是将所有数据存储在一个系统中,但这是错误的好处!您可能会争辩说您的代码也是一种数据形式,因此也可以存储在数据库中-您感觉如何?

除非您有一些特殊情况:

  • 业务逻辑属于代码。
  • 结构化数据属于数据库(关系或非关系)。
  • 批量数据属于存储(文件系统或其他)。

文件,代码,数据

不必使用文件系统来保存文件。相反,您可以在其上使用云存储(例如Amazon S3)或基础架构即服务(例如Uploadcare):

https://uploadcare.com/upload-api-cloud-storage-and-cdn/

但是将文件存储在数据库中不是一个好主意。



14

我知道这是旧帖子。但是,此页面的许多访问者都没有得到与该问题相关的信息。特别是对于新手。

如何在我们的网站上上传和存储图像或文件:

对于静态网站,可能没有问题,因为用于某些共享托管的文件存储仍然足够。问题出在动态网站变大时。可以处理数据库中较大的内容,但是图像等文件中的较大内容将成为问题。网站中有两种类型的图像:

  1. 图片来自动态博客的管理员。通常,这些图像在上传之前已经过优化。

  2. 来自用户的图像在用户的情况下被允许上传图像,例如化身。或者用户可以创建博客内容,并从文本编辑器中放置一些图像。这种图像很难预测尺寸。用户可以通过调整视图大小来上传仅用于较小内容的大图像,而不能调整图像大小。

通过忽略编号 以上1,快速解决方案编号。如果我们的网站中没有图像优化器功能,可以通过以下提示暂时解决2:

  1. 不允许用户通过将他们重定向到图库直接从文本编辑器上载。在此页面上,用户必须预先上传文件,然后才能嵌入内容中。此方法称为文件管理器。

  2. 使用裁剪图像功能供用户上传图像。即使用户上传很大的文件,这也会限制图像的大小。最终图像是裁剪图像的结果。我们可以在服务器端定义大小,并且仅接受例如500Kb或更低的大小。

现在,这只是暂时的。对于最终解决方案,重复此问题:

  • 如何处理大图像存储?
  • 调整大小或更改扩展名。
  • 大中型网站或电子商务如何处理其图像的文件存储?

我们可以做什么:

  1. 从共享托管VPS迁移。不够?然后通过升级到“专用”更高。

  2. 创建自己的服务器进行文件存储。谷歌搜索做到这一点。这并不像您想的那样困难。有人为他们的网站这样做。

  3. 简单的方法是使用CDN文件存储服务。

好吧,1和2有点贵。但是我认为没有3是最好的解决方案。

一些CDN服务允许您存储所需的任意数量的Web文件。

问题,“如何从我们的网站上载文件到CDN?”

不用担心,一旦注册(通常是免费),您将获得有关如何上传文件以及从/到您网站的链接的指导。您将获得一个API等。这很容易。

一些提供商会在有限的存储空间和带宽下为我们提供14天的免费服务。但这对于起点是可以的。唯一的问题是因为“人们从不尝试”。

希望对新手有帮助。


13

我们让客户在几个不同的后端上几次坚持使用选项B(数据库存储),最终我们总是最终回到选项A(文件系统存储)。

像SQL Server 2005这样的大型BLOB并没有得到很好的处理,这是我们尝试过的最新版本。

具体来说,我们看到了严重的膨胀,我认为可能是锁定问题。

另一个注意事项:如果您使用的是基于NTFS的存储(Windows服务器等),则可以考虑找到一种将成千上万个文件放在一个目录中的方法。我不确定为什么,但是有时文件系统不能很好地应对这种情况。如果有人对此有更多了解,我很想听听。

但是我总是尝试使用子目录来使事情分解。创建日期通常可以很好地达到以下目的:

图片/2008/12/17/.jpg

...这提供了不错的分离度,并且在调试过程中也有所帮助。当目录确实很大时,Explorer和FTP客户端都可能会感到有些不适。

编辑:只是2017年的一个简短说明,在SQL Server的最新版本中,有一些用于处理许多BLOB的新选项,可以避免我所讨论的缺点。

编辑:到2020年的快速说明,AWS / Azure / etc中的Blob存储多年来也已成为一种选择。这非常适合许多基于Web的项目,因为它很便宜,并且通常可以简化围绕部署,扩展到多台服务器以及在必要时调试其他环境等某些问题。


4
关于同一目录中文件数量的良好警告。它可能会导致在生产环境中很难发现的错误。
digao_mb 2014年

1
我以前遇到过这个问题。NTFS在一个文件夹中包含大约10,000个文件时表现异常。
Faiz 2015年

1
不仅是NTFS,而且还有BTRFS,这在处理一个文件夹中的大量图像时也存在问题。也就是说,如果您尝试这样做ls,将永远(挂起)。或删除。
sunapi386 '19

11

我最近创建了一个PHP / MySQL应用程序,该程序将PDF / Word文件存储在MySQL表中(到目前为止,每个文件最大40MB)。

优点:

  • 上载的文件将与其他所有文件一起复制到备份服务器,不需要单独的备份策略(请放心)。
  • 设置Web服务器稍微简单一些,因为我不需要上载/文件夹,也不必告诉我所有的应用程序在哪里。
  • 我可以使用事务进行编辑以提高数据完整性-我不必担心孤立和丢失的文件

缺点:

  • mysqldump现在花费了很多时间,因为其中一个表中有500MB的文件数据。
  • 与文件系统相比,整体内存/ CPU效率不高

我将我的实施称为成功,它可以满足备份要求并简化项目的布局。对于使用该应用程序的20至30个人而言,该性能很好。


6

我在网站上使用上传的图片,我肯定会说选项a)。

我强烈建议的另一件事是立即将文件名从用户命名的照片更改为更易于管理的文件名。例如,带有日期和时间的东西可以唯一地标识每张照片。

它还有助于去除用户文件名中的任何奇怪字符,以避免将来出现麻烦。


6

一定要调整图像的大小,如果可以,请检查其格式。曾经有过恶意文件被上载并通过不知情的主机提供服务的情况,例如,GIFAR漏洞使您可以在GIF文件中隐藏恶意的Java小程序,这样便可以在当前上下文中读取Cookie并将其发送到另一个站点进行跨站点脚本攻击。调整图像大小通常可以防止这种情况,因为这会破坏嵌入式代码。尽管此攻击已通过JVM修补程序修复,但天真地提供二进制文件而不清理它们会为您带来一系列漏洞。

请记住,大多数病毒扫描程序只能在文件系统上运行-如果将二进制文件存储在数据库中,将无法非常轻松地对它们运行扫描程序。



4

这基本上是我做的。

  1. 将上传的图像存储在临时目录或内存中。
  2. 在永久存储之前处理该图像。2.1。颜色校正2.2。压缩2.3。根据图像尺寸2.4创建多个副本。重命名为.xl,.lg,.md,.sm等后缀
  3. 将所有处理过的图像文件(来自单个文件)打包到一个文件夹中,文件夹名称id将与image file name(或可能是随机名称,作为图像名称)一起存储在数据库中的任何行/文档中。
  4. 如果不存在,请创建yyyy / mm / d path文件夹。例如2016/08/21 请记住,相同文件和行的路径和存储在数据库中。
  5. 将图像id文件path夹移动到文件夹。(路径文件夹可能位于/ var / web-content文件夹中。)
  6. 刷新内存缓冲区或删除临时文件。

当您需要访问文档中提到的任何图像时,您所拥有的文件夹的路径和ID会比包含图像的文件夹大。例如/var/web-content/{{path}}/{{id}}/image-file-name.sm.jpg

这样,如果您必须删除所有已处理的图像文件,只需递归删除文件夹及其内容即可。


3

大多数实现是选项A。

使用选项B,当您将数据库中的这些位编组到可以在浏览器中显示的内容时,您可以打开whoop4ss的一大罐……而且,如果数据库关闭,则图像不可用。

我认为空间不是一个大问题...太字节驱动器现在要几百美元。

我们之所以选择A,是因为我们没有时间或资源来做B。


3

对于自动调整大小,请尝试imagemagick ...它用于许多主要的开源内容/照片管理系统...,我相信它有一些.net扩展名。


2

我们使用A。我将其放在共享驱动器上(除非您不打算运行多台服务器)。

如果到了无法适应的时候,您可以研究缓存机制。


2

绝对肯定,选项A。其他人提到数据库通常不能很好地处理BLOB,无论它们是否设计为这样做。另一方面,文件系统正是为此而生。您可以选择使用RAID条带化,将映像分布在多个驱动器上,甚至将它们分布在地理位置不同的服务器上。

另一个优点是您的数据库备份/复制将非常麻烦。



2

出于安全原因,最好的做法是避免由IE的内容嗅探引起的问题,该问题可能使攻击者将JavaScript上传到图像文件中,而图像文件可能会在您的网站环境中执行。因此,您可能需要在存储图像之前以某种方式转换图像(裁剪/调整图像大小),以防止此类攻击。这个答案还有其他一些想法。


2

好吧,我有一个类似的项目,用户将文件上传到服务器上。以我的观点,选项a)由于更灵活,因此是最佳解决方案。您必须做的是将图像存储在按子目录分类的受保护的文件夹中。主目录必须由管理员设置,因为其内容必须没有运行脚本(非常重要)和(读,写)受保护的内容(因为它们不能在http请求中访问)。

我希望这可以帮助你。


1

如果它们是不需要编辑的小文件,则选项B并不是一个不错的选择。我更喜欢这样做,而不是编写逻辑来存储文件并处理疯狂的目录结构问题。有很多的文件在一个目录是坏的。恩凯?

如果文件很大或需要经常编辑,尤其是从Office之类的程序中进行编辑,则选项A是最好的选择。

在大多数情况下,这是一个优先选择的问题,但是如果您选择选项A,只需重新设置目录中没有太多文件即可。如果选择选项B,则将包含BLOBed数据的表置于其自己的数据库和/或文件组中。这将有助于维护,尤其是备份/还原。您的常规数据可能很小,而随着时间的推移,您的图像数据将非常庞大


1

这取决于您的要求,特别是数量,用户和搜索频率。但是,对于中小型办公室,最好的选择是使用Apple Photos或Adobe Lighroom之类的应用程序。它们专门用于存储,编目,索引和组织此类资源。但是,对于具有强大存储需求和大量用户的大型组织,建议使用诸如Nuxeo或Alfresco之类的数字资产管理实例化内容管理平台。两者都提供了很好的资源,并使用简化的方法来检索大量数据,从而管理它们。而且,非常重要:两个平台都有一个免费的(开源)选项。

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.