最近想做一个文件管理库,发现文件数量达到一定水平后,仅靠文件名很难管理文件。我想尝试其他方法来管理文件。这时,我想起了各种网盘工具中的“二次传输”功能。传输文件时,一次上传了几个G文件,实际上并没有传输。原理据说是计算文件的md5值,然后检查这个文件已经存在于系统中,所以没有必要上传它,并显示给用户”。
此外,每日使用的git在提交文件时也有类似的操作,但它使用sha1而不是md5。打开“你的文件已经秒传成功”。”目录,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,而是提取文件的一部分来计算哈希。因为不是文件的所有内容都是必需的。
对于太大的文件:文件大小内容
采样(first,middle,last或每xx字节采样一次hash),写了一段php代码来验证这个想法,发现可行。经过测试,没有高磁盘占用率,没有内存消耗,也没有性能问题。
函数文件_ MD5 _ 16k($ path){ 0
$ size=file size($ path);//获取文件大小
If($size16384){//如果文件大于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
返回MD5($ str);
}else{ //文件太小,不采样,直接计算整个文件的哈希。
返回MD5 _ file($ path);
}
}
这里,采样计算仅用于测试超过16kb的文件。在实际应用中,超过16kb的文件太小,超过16kb的文件太多,中间做一些改动会造成重复。应该设置大一点。
md5中存在重复的可能性。基于md5,结合文件类型、文件元信息等,可以唯一识别文件,避免文件重复,从而建立文件指纹数据库。
当然,要实现文件的“二次传输”,还有很多工作要做。这只是算法的实现原理。
下一篇:没有了