Files
kenaito-media-picker/internal/mover/mover.go
T
odboy e053b378fb feat: 增加 Web 管理界面,扫描整理改为页面点击触发
- main.go 改为 Web 服务入口(Gin + 内嵌前端 dist + 自动打开浏览器)
- internal/service: 新增扫描整理后台任务,支持状态机与实时日志捕获
- internal/api: 新增统一响应、媒体列表/统计、扫描开始/状态接口
- internal/store: 追加 ListMedia/CountMedia/Stats 查询,MediaInfo 补 JSON tag
- internal/config: application.properties 配置加载(端口/数据库/自动开浏览器)
- frontend: Vue2 + ElementUI + Vite 工程,含扫描整理/统计看板/媒体库三页
- build.sh 整合前端构建,输出单一 kenaito-media-picker.exe
2025-04-21 21:08:02 +08:00

103 lines
2.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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{}
// moveResult 移动结果状态
type moveResult int
const (
moveOK moveResult = iota // 移动成功(rename 或 copy+delete 完整完成)
movePartial // 复制成功但删除源失败,源与目标同时存在
moveFailed // 移动/复制失败
)
// 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 {
switch moveOne(src, targetDir) {
case moveOK, movePartial:
moved[src] = targetDir
}
bar.PrintBar(percent(i+1, total))
}
bar.PrintEnd("=== Finish")
return moved
}
// moveOne 移动单个文件;跨文件系统时 fallback 为 copy+delete
func moveOne(src, targetDir string) moveResult {
fileName := strings.ReplaceAll(uuid.NewV4().String(), "-", "") + "_" + filepath.Base(src)
target := filepath.Join(targetDir, fileName)
if err := os.Rename(src, target); err == nil {
return moveOK
}
if err := copyFile(src, target); err != nil {
fmt.Printf("=== 复制文件失败, 源: %s, 目标: %s, 错误: %v\n", src, target, err)
return moveFailed
}
if err := os.Remove(src); err != nil {
fmt.Printf("=== 警告: 复制成功但删除源文件失败, 源与目标同时存在, 源: %s, 错误: %v\n", src, err)
return movePartial
}
return moveOK
}
// 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
}
if _, err := io.Copy(out, in); err != nil {
out.Close()
_ = os.Remove(dst)
return err
}
if err := out.Close(); err != nil {
_ = os.Remove(dst)
return err
}
return nil
}
// percent 计算百分比(0~100)
func percent(part, total int) int {
if total <= 0 {
return 100
}
return int(float64(part) / float64(total) * 100)
}