最近想做一個文件管理庫,發現文件多到一定程度後只用文件名來管理有些困難,想嘗試下用其它方法來管理文件,這時想起來各類網盤工具中的「秒傳」功能,在傳文件時,幾個G的文件一下就傳上去了,但其實就沒傳,原理據說就是計算文件的md5值,然後檢查系統里已經有這個文件了,就不用在上傳了,給用戶顯示「你的文件已經秒傳成功」。
另外日常使用的git在提交文件時也有類似的操作,但用的不是md5而是sha1,打開「.git/objects/ 」目錄裡面就是sha1演算法生成的文件。
sha1和md5的作用是相同的,但sha1碰撞難度更高,有更好的安全性,但在一般情況下,md5就已經夠用了。
動手開始寫代碼,代碼運行起來後,遇到了第一個困難,”磁碟佔用率太高”,記得以前用機械硬碟時,windows動不動就磁碟佔用率100%,用了各種辦法都沒法解決,以為這是微軟在提示用戶,你的硬碟應該升級了,最後只好升級固態硬碟解決了這個問題,沒想到今天又遇到了這個問題。
我用的是php的md5_file()函數計算文件的md5值,當計算2G以上mp4文件的md5值時cpu 內存都正常,磁碟佔用卻率升到70%以上。於是我更換了編程語言,看是否還有這個問題。
首頁找到了一個python計算文件md5值的封裝,但測試下來也是一樣的問題,磁碟佔用率太高,於是又用上了js,在github找到了spark-md5.js這個庫,在瀏覽器前端計算文件的md5值,發現雖然沒有磁碟佔用率太高的問題,但瀏覽器的內存佔用又太高了。
於是就想能不能不判斷下文件大小,對太大的文件不計算md5了,結合文件大小,最後修改時間,創建時間等因素來做文件的唯一標識(找出文件有多少個副本),這個方法並不好,因為文件的元信息是可以隨意改動的,要造出兩個元信息完全一致的文件並不困難。
經人指點後,感覺還是要用md5才行,但對於太大的文件,可以並不計算整個文件的md5,而是抽取文件部分內容計算hash。因為並不需要文件的全部內容。
對於太大的文件使用:文件大小+內容
抽樣(頭、中、尾或每隔xx位元組抽樣一次哈希),寫了一段php代碼來驗證這一思路,發現可行。測試下來沒有磁碟佔用率太高的情況,也不吃內存,沒有性能問題,
function file_md5_16k($path){
$size=filesize($path);//取得文件大小
if($size>16384){//如果文件大於16kb
$str=$size;
$str.=file_get_contents($path,null,null,0,4096);#文件頭部4kb
$str.=file_get_contents($path,null,null,(($size/2)-2048),4096);#文件中部4kb
$str.=file_get_contents($path,null,null,($size-4096),4096);#文件尾部4kb
return md5($str);
}else{ //文件不太,不抽樣,直接計算整個文件的hash
return md5_file($path);
}
}這裡只是測試16kb以上的文件就用了抽樣計算,實際應用中16k的文件太小了,大於16kb的文件太多,中間修改了一些內容很會產生重複。應該設置的更大一些。
md5存在重複可能,在md5基礎上再結合文件類型,文件元信息等就可以對文件做唯一標識,避免文件重複,從而建立文件指紋庫。
當然要實現文件「秒傳」要做的遠遠不止這些,這個只是實現原理演算法。
原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/226488.html
微信掃一掃
支付寶掃一掃