refactor: 全面重构代码并加白话注释,移动全局并行,去掉去向/重复记录
- 重构后端与前端,全程大白话注释(不懂程序也能看懂) - 移动阶段改为全局并行(MoveAll,工人数=CPU核心数) - 去掉记录每个文件搬去哪了(删除去向回填,解决写库卡顿) - 去掉重复文件标记与统计:重复判定改为 MD5+路径都相同才算,重复则原地忽略不移动;MD5 相同但路径不同仍照常搬 - 媒体库去掉归类目录列,看板去掉重复/归类分布统计
This commit is contained in:
@@ -1,4 +1,12 @@
|
||||
// Package digest 提供文件 MD5 与指纹采样计算,供媒体入库时复用。
|
||||
// Package digest 负责给文件算"身份证号"(MD5),以及一种偷懒的指纹算法。
|
||||
//
|
||||
// 大白话理解:
|
||||
// - MD5:把整个文件的内容算出一串固定长度的数字,内容一样 MD5 就一样,
|
||||
// 所以可以用它来判断"两个文件是不是一模一样"。
|
||||
// - 指纹:大文件(几 GB 的视频)算全量 MD5 很慢。于是只读文件"开头 256KB
|
||||
// 和结尾 256KB"各算一个 MD5,加上文件大小,凑成一个"指纹"。
|
||||
// 指纹一样基本就说明是同一个文件——先用它去数据库碰碰运气,
|
||||
// 能对上就直接复用已有的 MD5,省掉全量计算。
|
||||
package digest
|
||||
|
||||
import (
|
||||
@@ -9,13 +17,14 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// FingerprintThreshold 文件大于该字节数才使用指纹复用,避免全量MD5
|
||||
// FingerprintThreshold 文件大于这个字节数(1MB)才值得用指纹偷懒;
|
||||
// 小文件全量算 MD5 也没多慢,没必要麻烦。
|
||||
FingerprintThreshold = 1 << 20
|
||||
fingerprintHeadSize = 256 << 10 // 文件头采样256KB
|
||||
fingerprintTailSize = 256 << 10 // 文件尾采样256KB
|
||||
fingerprintHeadSize = 256 << 10 // 文件开头采样 256KB
|
||||
fingerprintTailSize = 256 << 10 // 文件结尾采样 256KB
|
||||
)
|
||||
|
||||
// CalcFileMd5 计算文件MD5(分块读取,适合大文件)
|
||||
// CalcFileMd5 计算整个文件的 MD5。分块读取,大文件也能吃下不占太多内存。
|
||||
func CalcFileMd5(filePath string) (string, error) {
|
||||
file, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
@@ -29,18 +38,22 @@ func CalcFileMd5(filePath string) (string, error) {
|
||||
return hex.EncodeToString(h.Sum(nil)), nil
|
||||
}
|
||||
|
||||
// CalcFileFingerprint 计算文件头部与尾部采样MD5(只读取很少字节,用于快速识别相同文件)
|
||||
// CalcFileFingerprint 计算文件的"指纹":开头 256KB 的 MD5 + 结尾 256KB 的 MD5。
|
||||
// 只读很少一点字节,用来快速判断"是不是和之前见过的文件一样"。
|
||||
// 注意:文件大小必须大于开头+结尾采样的大小(即大于 512KB),否则读不满,会报错。
|
||||
func CalcFileFingerprint(filePath string, size int64) (headMd5, tailMd5 string, err error) {
|
||||
file, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
defer file.Close()
|
||||
// 开头 256KB
|
||||
h := md5.New()
|
||||
if _, err := io.CopyN(h, file, fingerprintHeadSize); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
headMd5 = hex.EncodeToString(h.Sum(nil))
|
||||
// 跳到"结尾往前 256KB"的位置,再读 256KB
|
||||
h = md5.New()
|
||||
if _, err := file.Seek(size-fingerprintTailSize, io.SeekStart); err != nil {
|
||||
return "", "", err
|
||||
|
||||
Reference in New Issue
Block a user