- 删除 vars 全局状态,按职责拆分 internal/ 包:scanner/probe/classify/organize/mover/store/digest - 数据驱动归类规则替代图片/视频重复分支,store 改为结构体实例 - build.sh 按系统类型编译:Windows 用 upx 压缩,macOS/Linux 不压缩 - 忽略目录拆分:图片_已忽略 / 视频_已忽略 - 输出构建产物加入 .gitignore
89 lines
2.2 KiB
Go
89 lines
2.2 KiB
Go
// Package mover 负责文件的移动,跨文件系统时自动回退为复制后删除。
|
||
package mover
|
||
|
||
import (
|
||
"fmt"
|
||
"io"
|
||
"os"
|
||
"path/filepath"
|
||
"strings"
|
||
|
||
"github.com/redmask-hb/GoSimplePrint/goPrint"
|
||
uuid "github.com/satori/go.uuid"
|
||
)
|
||
|
||
// Mover 文件移动器
|
||
type Mover struct{}
|
||
|
||
// MoveToDir 将一批文件移动到目标目录(目标文件名使用 uuid 前缀防止同名覆盖)。
|
||
// 返回移动成功的 源路径 → 目标目录 映射,供记录去向使用。
|
||
func (m *Mover) MoveToDir(filePaths []string, targetDir string) map[string]string {
|
||
moved := make(map[string]string)
|
||
if len(filePaths) == 0 {
|
||
return moved
|
||
}
|
||
if err := os.MkdirAll(targetDir, 0755); err != nil {
|
||
fmt.Printf("=== 创建目录失败: %s, 错误: %v\n", targetDir, err)
|
||
return moved
|
||
}
|
||
|
||
bar := goPrint.NewBar(100)
|
||
bar.SetNotice("=== 移动文件到目录:")
|
||
bar.SetGraph(">")
|
||
total := len(filePaths)
|
||
for i, src := range filePaths {
|
||
if moveOne(src, targetDir) {
|
||
moved[src] = targetDir
|
||
}
|
||
bar.PrintBar(percent(i+1, total))
|
||
}
|
||
bar.PrintEnd("=== Finish")
|
||
return moved
|
||
}
|
||
|
||
// moveOne 移动单个文件;跨文件系统时 fallback 为 copy+delete
|
||
func moveOne(src, targetDir string) bool {
|
||
fileName := strings.ReplaceAll(uuid.NewV4().String(), "-", "") + "_" + filepath.Base(src)
|
||
target := filepath.Join(targetDir, fileName)
|
||
if err := os.Rename(src, target); err == nil {
|
||
return true
|
||
}
|
||
if err := copyFile(src, target); err != nil {
|
||
fmt.Printf("=== 复制文件失败, 源: %s, 目标: %s, 错误: %v\n", src, target, err)
|
||
return false
|
||
}
|
||
if err := os.Remove(src); err != nil {
|
||
fmt.Printf("=== 删除源文件失败: %s, 错误: %v\n", src, err)
|
||
// 复制成功但删除失败,文件已存在于两处,视为移动成功
|
||
}
|
||
return true
|
||
}
|
||
|
||
// copyFile 逐块复制文件
|
||
func copyFile(src, dst string) error {
|
||
in, err := os.Open(src)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
defer in.Close()
|
||
|
||
out, err := os.Create(dst)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
defer out.Close()
|
||
|
||
if _, err := io.Copy(out, in); err != nil {
|
||
return err
|
||
}
|
||
return out.Close()
|
||
}
|
||
|
||
// percent 计算百分比(0~100)
|
||
func percent(part, total int) int {
|
||
if total <= 0 {
|
||
return 100
|
||
}
|
||
return int(float64(part) / float64(total) * 100)
|
||
}
|