161

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

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

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

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

4

18 回答 18

105

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

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

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

于 2008-12-08T00:03:20.603 回答
51

选项 B 的唯一好处是在一个系统中拥有所有数据,但这是一个错误的好处!你可能会争辩说你的代码也是一种数据形式,因此也可以存储在数据库中——你喜欢它吗?

除非你有一些独特的情况:

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

文件、代码、数据

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

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

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

于 2014-11-26T13:53:40.363 回答
23

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

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

对于静态网站可能没有问题,因为某些共享托管的文件存储仍然足够。问题来自一个动态的网站,当它变大时。可以处理更大的数据库,但更大的文件(例如图像)成为问题。网站中有两种类型的图像:

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

  2. 来自用户的图片,如果用户允许上传头像等图片。或者用户可以创建博客内容并从文本编辑器中放置一些图像。这种图像很难预测大小。用户可以通过调整视图大小而不是调整图像大小来为小内容上传大图像。

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

  1. 不允许用户通过将用户重定向到图片库来直接从文本编辑器上传。在此页面上,用户必须提前上传文件才能嵌入内容。此方法称为文件管理器。

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

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

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

那么我们可以做什么:

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

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

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

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

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

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

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

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

希望对新手有所帮助。

于 2016-12-01T11:40:29.107 回答
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 的项目,因为它价格便宜,并且通常可以简化有关部署、扩展到多台服务器、在必要时调试其他环境等方面的某些问题。

于 2008-12-08T02:06:50.573 回答
12

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

优点:

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

缺点:

  • mysqldump 现在需要很长时间,因为其中一个表中有 500MB 的文件数据。
  • 与文件系统相比,总体而言内存/cpu 效率不是很高

我认为我的实现是成功的,它处理了备份需求并简化了项目的布局。对于使用该应用程序的 20-30 人来说,性能很好。

于 2008-12-08T04:29:55.683 回答
10

一定要调整图像的大小,如果可以的话,检查它的格式。有一些恶意文件被不知情的主机上传和提供服务的案例——例如,GIFAR漏洞允许您在 GIF 文件中隐藏恶意 Java 小程序,然后能够读取当前上下文中的 cookie 并将它们发送到另一个用于跨站点脚本攻击的站点。调整图像大小通常可以防止这种情况发生,因为它会破坏嵌入的代码。虽然这种攻击已被 JVM 补丁修复,但天真地提供二进制文件而不清理它们会使您面临一系列漏洞。

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

于 2008-12-08T02:19:53.493 回答
8

这基本上是我做的。

  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 年 8 月 21 日。记住该路径并存储在数据库中以获取相同的文档和行。
  5. 将图像文件夹移动idpath文件夹。(路径文件夹可能位于 /var/web-content 文件夹中。)
  6. 刷新内存缓冲区或删除临时文件。

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

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

于 2016-06-29T16:17:13.763 回答
7

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

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

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

于 2008-12-08T02:12:25.287 回答
5

在 SQL Server 2008 中有一种混合方法,称为文件流数据类型,在RunAs Radio #74上讨论过,这有点像两全其美。大多数人没有 2008 年的选项,但如果你有,这个选项看起来很酷

于 2008-12-09T05:15:10.270 回答
3

大多数实现是选项 A。

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

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

我们正在使用选项 A 实施,因为我们没有时间或资源来执行选项 B。

于 2008-12-08T00:40:29.263 回答
3

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

于 2008-12-08T01:58:15.223 回答
2

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

如果到时候这对您来说无法扩展,那么您可以研究缓存机制。

于 2008-12-08T00:03:56.513 回答
2

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

另一个优点是您的数据库备份/复制将是巨大的。

于 2008-12-08T01:46:47.900 回答
2

选项 A。

加载图像后,您可以在保存之前验证格式并调整其大小。http://www.codeproject.com上有许多 .Net 代码示例可以调整图像大小。例如: http: //www.codeproject.com/KB/cs/Photo_Resize.aspx

于 2008-12-09T04:40:26.720 回答
2

出于安全原因,最好的做法也是避免IE 的内容嗅探引起的问题,这可能允许攻击者在图像文件中上传 JavaScript,这些文件可能会在您的站点上下文中执行。因此,您可能希望在存储图像之前以某种方式转换图像(裁剪/调整大小)以防止这种攻击。这个答案有一些其他的想法。

于 2011-01-13T03:38:51.220 回答
2

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

我希望这可以帮助你。

于 2012-04-06T14:52:17.250 回答
1

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

如果文件很大或需要不断编辑,尤其是来自 office 等程序,那么选项 A 是您的最佳选择。

在大多数情况下,这是一个偏好问题,但如果您选择选项 A,只需使目录中没有太多文件即可。如果您选择选项 B,则将带有 BLOBed 数据的表放在它自己的数据库和/或文件组中。这将有助于维护,尤其是备份/恢复。您的常规数据可能相当小,而您的图像数据会随着时间的推移而变得庞大。

于 2008-12-09T05:11:25.847 回答
1

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

于 2016-11-18T15:43:33.560 回答