25

我正在开发一种将文件存储在文件系统中的软件,以及对数据库中这些文件的引用。因此可以在数据库中查询上传的文件,而无需访问文件系统。从我在其他帖子中读到的内容来看,大多数人说最好使用文件系统进行文件存储,而不是将二进制数据作为 BLOB 直接存储在数据库中。

所以现在我试图了解设置它的最佳方法,以便数据库和文件系统保持同步,并且我不会最终引用不存在的文件,或者文件占用空间未引用的文件系统。以下是我正在考虑的几个选项。

选项 1:首先添加文件引用

//Adds a reference to a file in the database
database.AddFileRef("newfile.txt"); 

//Stores the file in the file system
fileStorage.SaveFile("newfile.txt",dataStream); 

这个选项会有问题,因为对文件的引用是在实际文件之前添加的,因此另一个用户可能最终会在文件实际存储在系统中之前尝试下载文件。虽然,由于对文件的引用是事先创建的,因此在存储文件时可以使用主键值。

选项 2:首先存储文件

//Stores the file
fileStorage.SaveFile("newfile.txt",dataStream); 

//Adds a reference to the file in the database
//fails if reference file does not existing in file system
database.AddFileRef("newfile.txt"); 

此选项更好,但可以让某人将文件上传到从未被引用的系统。虽然这可以通过删除任何未引用文件的“Purge”或“CleanUpFileSystem”功能来解决。此选项也不允许使用数据库中的主键值存储文件。

选项 3:待定状态

//Adds a pending file reference to database
//pending files would be ignored by others
database.AddFileRef("newfile.txt"); 

//Stores the file, fails if there is no 
//matching pending file reference in the database
fileStorage.SaveFile("newfile.txt",dataStream); database

//marks the file reference as committed after file is uploaded
database.CommitFileRef("newfile.txt"); 

此选项允许在文件上传之前创建主键,但也可以防止其他用户在文件上传之前获得对文件的引用。虽然,文件可能永远不会被上传,并且文件引用可能会被挂起。然而,从数据库中清除待处理的引用也是相当简单的。

我倾向于选项 2,因为它很简单,而且我不必担心用户在上传文件之前会尝试请求文件。存储很便宜,所以如果我最终得到一些未引用的文件占用空间,这并不是世界末日。但这似乎也是一个常见问题,我想听听其他人如何解决它或我应该考虑的其他因素。

4

3 回答 3

3

我想提出另一种选择。使文件名始终等于其内容的哈希值。然后,您可以随时安全地编写任何内容,前提是您在其他地方添加对它的引用之前这样做。

由于内容永远不会改变,因此永远不会出现同步问题。

这为您提供了免费的重复数据删除功能。删除变得更加困难。我推荐一个夜间垃圾收集过程。

于 2013-03-15T19:00:08.153 回答
0

数据库的真正用途是什么?如果它只是一个文件列表,我认为您根本不需要它,并且没有它可以为您节省同步的麻烦。

如果您确信您需要它,那么从技术角度来看,选项 1 和 2 完全相同——这两个资源可能不同步,您需要一个常规流程来再次整合它们。所以在这里你应该选择最适合应用程序的选项。

选项 3 没有任何优势,但会使用更多资源。

请注意,按照 usr 的建议,使用散列具有理论上的冲突风险。而且你还需要一个定期整合过程,就像选项 1 和 2 一样。

另一个问题是您如何处理部分上传和正在进行的上传。这里可以使用选项 2,但您也可以使用在上传开始之前创建的第二个“标志”文件,并在上传完成后删除。这将帮助您确定哪些上传已被中止。

于 2013-03-15T19:15:01.063 回答
0

为了弥补您提到的选项 1的缺点,我使用类似的东西fileStorage.FileExists("newfile.txt");并过滤掉它返回负数的结果。

Python行话:

import os
op = os.path

filter(lambda ref: op.exists(ref.path()), database.AllRefs())
于 2013-08-07T10:06:23.907 回答