// Package digest 提供文件 MD5 与指纹采样计算,供媒体入库时复用。 package digest import ( "crypto/md5" "encoding/hex" "io" "os" ) const ( // FingerprintThreshold 文件大于该字节数才使用指纹复用,避免全量MD5 FingerprintThreshold = 1 << 20 fingerprintHeadSize = 256 << 10 // 文件头采样256KB fingerprintTailSize = 256 << 10 // 文件尾采样256KB ) // CalcFileMd5 计算文件MD5(分块读取,适合大文件) func CalcFileMd5(filePath string) (string, error) { file, err := os.Open(filePath) if err != nil { return "", err } defer file.Close() h := md5.New() if _, err := io.Copy(h, file); err != nil { return "", err } return hex.EncodeToString(h.Sum(nil)), nil } // CalcFileFingerprint 计算文件头部与尾部采样MD5(只读取很少字节,用于快速识别相同文件) func CalcFileFingerprint(filePath string, size int64) (headMd5, tailMd5 string, err error) { file, err := os.Open(filePath) if err != nil { return "", "", err } defer file.Close() h := md5.New() if _, err := io.CopyN(h, file, fingerprintHeadSize); err != nil { return "", "", err } headMd5 = hex.EncodeToString(h.Sum(nil)) h = md5.New() if _, err := file.Seek(size-fingerprintTailSize, io.SeekStart); err != nil { return "", "", err } if _, err := io.CopyN(h, file, fingerprintTailSize); err != nil { return "", "", err } tailMd5 = hex.EncodeToString(h.Sum(nil)) return headMd5, tailMd5, nil }