2013-03-15 71 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())