2013-03-15 67 views
14

我正在研究将文件存储在文件系统中的软件,以及对数据库中这些文件的引用。查询上传的文件可以在数据库中完成,而无需访问文件系统。根据我在其他文章中阅读的内容,大多数人认为最好使用文件系统进行文件存储,而不是直接将二进制数据作为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"); 

此选项是更好的,但将有可能有人上传文件到不会被引用的系统。尽管可以通过“清除”或“清理文件系统”功能来解决这个问题,该功能会删除所有未引用的文件。该选项也不允许使用数据库中的主键值存储文件。

选项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,因为它很简单,而且我不必担心用户在上传文件之前请求文件。存储是便宜的,所以如果我最终得到一些未引用的文件占用空间,那么它不是世界末日。但这似乎也是一个常见问题,我想听听其他人是如何解决它或我应该做的其他考虑。

+1

很聪明的问题。许多人从不考虑他们不同的数据存储之间的一致性。 – usr 2013-03-15 19:01:08

回答

2

我想提出另一种选择。使文件名始终等于其内容的散列。然后,您可以在任何时候安全地编写任何内容,前提是您在向其他地方添加引用之前执行此操作。

由于内容永远不会改变,所以永远不会有同步问题。

这给你免费的重复数据删除。尽管删除变得更困难。我建议每晚垃圾收集过程。

+0

你能详细说明一下吗?我会从文件中获取散列码,并使用该代码来确定文件如何存储在文件系统中?然后,数据库将对文件的引用存储为散列码,而不是文件名?难道我不得不处理碰撞的可能性吗? – 2013-03-15 19:09:35

+1

如果你使用标准的加密散列函数,你根本不必处理冲突(如果你确实已经赢了10次彩票)。旧的MD5算法已经足够好,可以随处安装,也是最快的算法之一。你首先要确定散列,然后从它中派生一个文件名('tohex(hashbytes)+“.dat”')并写入它。然后将散列(或文件名)存储在数据库中。完成。 – usr 2013-03-15 19:30:41

0

数据库的真正用途是什么?如果它只是一个文件列表,我认为你根本不需要它,并且不会让它省去同步的麻烦。

如果您确信自己需要它,则从技术角度来看,选项1和2完全相同 - 这2个资源可能不同步,您需要定期处理以再次合并它们。所以在这里您应该选择最适合应用的选项。

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

请注意,使用散列,正如usr所建议的那样,承担理论上的碰撞风险。而且您还需要定期合并流程,如选项1和2.

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

+1

还有其他非二进制信息存储在数据库中,这是相关的文件,所以是的,我需要它。 – 2013-03-15 19:45:53

0

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

Python行话

import os 
op = os.path 

filter(lambda ref: op.exists(ref.path()), database.AllRefs())