package upload import ( "errors" "io" "mime/multipart" "os" "path/filepath" "strings" "sync" "time" "kra/pkg/utils" ) var mu sync.Mutex // Local 本地存储 type Local struct { StorePath string BasePath string } // NewLocal 创建本地存储 func NewLocal(storePath, basePath string) *Local { return &Local{ StorePath: storePath, BasePath: basePath, } } // UploadFile 上传文件 func (l *Local) UploadFile(file *multipart.FileHeader) (string, string, error) { // 读取文件后缀 ext := filepath.Ext(file.Filename) // 读取文件名并加密 name := strings.TrimSuffix(file.Filename, ext) name = utils.MD5V([]byte(name)) // 拼接新文件名 filename := name + "_" + time.Now().Format("20060102150405") + ext // 尝试创建此路径 mkdirErr := os.MkdirAll(l.StorePath, os.ModePerm) if mkdirErr != nil { return "", "", errors.New("function os.MkdirAll() failed, err:" + mkdirErr.Error()) } // 拼接路径和文件名 p := l.StorePath + "/" + filename filePath := l.BasePath + "/" + filename f, openError := file.Open() // 读取文件 if openError != nil { return "", "", errors.New("function file.Open() failed, err:" + openError.Error()) } defer f.Close() out, createErr := os.Create(p) if createErr != nil { return "", "", errors.New("function os.Create() failed, err:" + createErr.Error()) } defer out.Close() _, copyErr := io.Copy(out, f) // 传输(拷贝)文件 if copyErr != nil { return "", "", errors.New("function io.Copy() failed, err:" + copyErr.Error()) } return filePath, filename, nil } // DeleteFile 删除文件 func (l *Local) DeleteFile(key string) error { // 检查 key 是否为空 if key == "" { return errors.New("key不能为空") } // 验证 key 是否包含非法字符或尝试访问存储路径之外的文件 if strings.Contains(key, "..") || strings.ContainsAny(key, `\/:*?"<>|`) { return errors.New("非法的key") } p := filepath.Join(l.StorePath, key) // 检查文件是否存在 if _, err := os.Stat(p); os.IsNotExist(err) { return errors.New("文件不存在") } // 使用文件锁防止并发删除 mu.Lock() defer mu.Unlock() err := os.Remove(p) if err != nil { return errors.New("文件删除失败: " + err.Error()) } return nil }