Files
kenaito-media-picker/util/file.go
T
odboy 066e28a2d6 feat(core): 优化媒体文件扫描和处理功能
- 添加跳过ffprobe相关文件的逻辑,避免处理临时释放文件
- 修复图片处理中的变量引用错误
- 实现大文件指纹复用机制,避免重复全量读取计算MD5
- 新增文件头尾采样指纹算法,提升大文件处理性能
- 重构ffprobe内嵌资源管理,支持多平台自动选择对应版本
- 添加媒体信息数据库的指纹索引和去向跟踪功能
- 优化程序启动流程,失败时跳过媒体整理但保留图片处理
- 更新文档说明多平台ffprobe支持和构建要求
2025-03-21 21:00:59 +08:00

163 lines
5.1 KiB
Go

package util
import (
"crypto/md5"
"encoding/hex"
"fmt"
"github.com/gabriel-vasile/mimetype"
"io"
"io/ioutil"
"os"
"path/filepath"
)
// CreateDir 创建目录(含递归创建父目录)
func CreateDir(dirPath string) bool {
err := os.MkdirAll(dirPath, 0755)
if err != nil {
fmt.Printf("=== 创建目录失败: %s, 错误: %v\n", dirPath, err)
}
return err == nil
}
// GetFileDirectory 获取文件所在文件夹
func GetFileDirectory(filePath string) string {
directoryPath, _ := filepath.Split(filePath)
return directoryPath
}
// ReadFileMimeInfo 获取文件mime信息,失败时返回nil
func ReadFileMimeInfo(filepath string) *mimetype.MIME {
mt, err := mimetype.DetectFile(filepath)
if err != nil {
fmt.Printf("=== 读取Mime信息失败: %s, 错误: %v\n", filepath, err)
return nil
}
return mt
}
// CheckFileIsExist 判断文件是否存在,存在返回 true,不存在返回false
func CheckFileIsExist(filename string) bool {
var exist = true
if _, err := os.Stat(filename); os.IsNotExist(err) {
exist = false
}
return exist
}
// WriteByteArraysToFile 写字节数组到文件
func WriteByteArraysToFile(content []byte, filename string) error {
return ioutil.WriteFile(filename, content, 0777)
}
// 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
}
// MD5指纹加速相关常量
const (
FingerprintThreshold = 1 << 20 // 文件大于1MB才使用指纹复用,避免全量MD5
fingerprintHeadSize = 256 << 10 // 文件头采样256KB
fingerprintTailSize = 256 << 10 // 文件尾采样256KB
)
// CalcFileFingerprint 计算文件的头部与尾部采样MD5(只读取很少字节,用于快速识别相同文件)
func CalcFileFingerprint(filePath string, size int64) (headMd5 string, 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
}
//// 移动文件到根目录
//func renameFile(rootDir string, modelType string, videoList []string, pathSeparator string) {
// total := len(videoList)
// var count = 0
// bar := goPrint.NewBar(100)
// bar.SetNotice("=== 重命名文件:")
// bar.SetGraph(">")
// for _, videoFilePath := range videoList {
// wh := videoPath2WidthHeightTagMap[videoFilePath]
// fileName := vars.GlobalFilePath2FileNameMap[videoFilePath]
// if strings.Contains(fileName, videoTag) { // 处理过了
// fileNames := strings.Split(fileName, videoTag)
// if len(fileNames) == 2 {
// fileName = fileNames[1]
// targetFilePath := rootDir + pathSeparator + "[" + videoPath2DurationMap[videoFilePath] + "]" + modelType + wh + videoTag + fileName
// err := os.Rename(videoFilePath, targetFilePath)
// if err != nil {
// fmt.Printf("=== 重命名异常: %s \n", videoFilePath)
// }
// }
// } else {
// targetFilePath := rootDir + pathSeparator + "[" + videoPath2DurationMap[videoFilePath] + "]" + modelType + wh + videoTag + " - " + fileName
// err := os.Rename(videoFilePath, targetFilePath)
// if err != nil {
// fmt.Printf("=== 重命名异常: %s \n", videoFilePath)
// }
// }
// count = count + 1
// bar.PrintBar(util.CalcPercentage(count, total))
// }
// bar.PrintEnd("=== Finish")
//}
//
//// 移动文件到原目录
//func renameFileV2(modelType string, videoList []string) {
// total := len(videoList)
// var count = 0
// bar := goPrint.NewBar(100)
// bar.SetNotice("=== 重命名文件:")
// bar.SetGraph(">")
// for _, videoFilePath := range videoList {
// wh := videoPath2WidthHeightTagMap[videoFilePath]
// fileName := vars.GlobalFilePath2FileNameMap[videoFilePath]
// filePath := util.GetFileDirectory(videoFilePath)
// if strings.Contains(fileName, videoTag) { // 处理过了
// fileNames := strings.Split(fileName, videoTag)
// if len(fileNames) == 2 {
// fileName = fileNames[1]
// targetFilePath := filePath + "[" + videoPath2DurationMap[videoFilePath] + "]" + modelType + wh + videoTag + fileName
// err := os.Rename(videoFilePath, targetFilePath)
// if err != nil {
// fmt.Printf("=== 重命名异常: %s \n", videoFilePath)
// }
// }
// } else {
// targetFilePath := filePath + "[" + videoPath2DurationMap[videoFilePath] + "]" + modelType + wh + videoTag + " - " + fileName
// err := os.Rename(videoFilePath, targetFilePath)
// if err != nil {
// fmt.Printf("=== 重命名异常: %s \n", videoFilePath)
// }
// }
// count = count + 1
// bar.PrintBar(util.CalcPercentage(count, total))
// }
// bar.PrintEnd("=== Finish")
//}