refactor: 按模块重构项目结构
- 删除 vars 全局状态,按职责拆分 internal/ 包:scanner/probe/classify/organize/mover/store/digest - 数据驱动归类规则替代图片/视频重复分支,store 改为结构体实例 - build.sh 按系统类型编译:Windows 用 upx 压缩,macOS/Linux 不压缩 - 忽略目录拆分:图片_已忽略 / 视频_已忽略 - 输出构建产物加入 .gitignore
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
// 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
|
||||
}
|
||||
Reference in New Issue
Block a user