package main import ( "fmt" "io" "os" "path/filepath" "runtime" "strings" "time" ) // SafeCreateFile 安全地创建文件,如果文件已存在或被占用,则创建新名称的文件 func SafeCreateFile(filePath string) (*os.File, string, error) { // 确保目录存在 dir := filepath.Dir(filePath) if err := os.MkdirAll(dir, 0755); err != nil { return nil, "", fmt.Errorf("创建目录失败: %v", err) } // 尝试直接创建文件 file, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) if err == nil { return file, filePath, nil } // 如果文件被占用或存在其他问题,尝试创建带时间戳的新文件名 baseDir := filepath.Dir(filePath) fileName := filepath.Base(filePath) ext := filepath.Ext(fileName) nameWithoutExt := strings.TrimSuffix(fileName, ext) // 生成新的文件名 newFileName := fmt.Sprintf("%s_%d%s", nameWithoutExt, time.Now().UnixNano(), ext) newFilePath := filepath.Join(baseDir, newFileName) // 尝试创建新文件 file, err = os.OpenFile(newFilePath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) if err != nil { return nil, "", fmt.Errorf("创建文件失败: %v", err) } return file, newFilePath, nil } // SafeCreateFileWithRetry 安全创建文件,支持重试机制 func SafeCreateFileWithRetry(filePath string, maxRetries int) (*os.File, string, error) { if maxRetries <= 0 { maxRetries = 3 } for i := 0; i < maxRetries; i++ { file, newPath, err := SafeCreateFile(filePath) if err == nil { return file, newPath, nil } // 最后一次尝试不等待 if i < maxRetries-1 { time.Sleep(time.Millisecond * 100 * time.Duration(i+1)) } } return nil, "", fmt.Errorf("重试%d次后仍无法创建文件: %s", maxRetries, filePath) } // GenerateUniqueFileName 生成唯一的文件名 func GenerateUniqueFileName(originalPath string) string { baseDir := filepath.Dir(originalPath) fileName := filepath.Base(originalPath) ext := filepath.Ext(fileName) nameWithoutExt := strings.TrimSuffix(fileName, ext) // 使用时间戳和随机数生成唯一名称 uniqueSuffix := fmt.Sprintf("_%d%d", time.Now().UnixNano(), time.Now().Nanosecond()) return filepath.Join(baseDir, nameWithoutExt+uniqueSuffix+ext) } // CheckFileExists 检查文件是否存在 func CheckFileExists(filePath string) bool { _, err := os.Stat(filePath) return !os.IsNotExist(err) } // DeleteFileIfExists 如果文件存在则删除 func DeleteFileIfExists(filePath string) error { if CheckFileExists(filePath) { return os.Remove(filePath) } return nil } // SafeWriteFile 安全写入文件内容,处理文件占用问题 func SafeWriteFile(filePath string, data []byte) (string, error) { file, newPath, err := SafeCreateFile(filePath) if err != nil { return "", err } defer file.Close() _, err = file.Write(data) if err != nil { return "", err } return newPath, nil } // SafeWriteFileWithRetry 安全写入文件内容,支持重试 func SafeWriteFileWithRetry(filePath string, data []byte, maxRetries int) (string, error) { file, newPath, err := SafeCreateFileWithRetry(filePath, maxRetries) if err != nil { return "", err } defer file.Close() _, err = file.Write(data) if err != nil { return "", err } return newPath, nil } // GetFileSize 获取文件大小 func GetFileSize(filePath string) (int64, error) { info, err := os.Stat(filePath) if err != nil { return 0, err } return info.Size(), nil } // CopyFile 安全复制文件 func CopyFile(src, dst string) error { sourceFile, err := os.Open(src) if err != nil { return err } defer sourceFile.Close() destFile, _, err := SafeCreateFile(dst) if err != nil { return err } defer destFile.Close() _, err = io.Copy(destFile, sourceFile) return err } // GetTempDir 获取临时目录路径 func GetTempDir() string { tempDir := os.TempDir() if runtime.GOOS == "windows" { // Windows系统,确保使用正确的路径分隔符 tempDir = strings.ReplaceAll(tempDir, "\\", "/") } return tempDir } // CreateTempFile 在临时目录创建文件 func CreateTempFile(prefix, suffix string) (*os.File, string, error) { tempDir := GetTempDir() fileName := fmt.Sprintf("%s_%d%s", prefix, time.Now().UnixNano(), suffix) filePath := filepath.Join(tempDir, fileName) file, err := os.Create(filePath) if err != nil { return nil, "", err } return file, filePath, nil } // MoveFile 安全移动文件 func MoveFile(src, dst string) error { // 确保目标目录存在 if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil { return fmt.Errorf("创建目标目录失败: %v", err) } // 尝试直接重命名 if err := os.Rename(src, dst); err == nil { return nil } // 如果重命名失败,尝试复制然后删除源文件 if err := CopyFile(src, dst); err != nil { return fmt.Errorf("复制文件失败: %v", err) } return os.Remove(src) } // CleanOldFiles 清理指定目录下的旧文件 func CleanOldFiles(dir string, daysToKeep int) error { if daysToKeep <= 0 { daysToKeep = 7 // 默认保留7天 } cutoffTime := time.Now().AddDate(0, 0, -daysToKeep) return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { if err != nil { return nil // 跳过错误 } if !info.IsDir() && info.ModTime().Before(cutoffTime) { os.Remove(path) } return nil }) } // GetFileExtension 获取文件扩展名(包含点) func GetFileExtension(filename string) string { return filepath.Ext(filename) } // GetFileNameWithoutExt 获取不带扩展名的文件名 func GetFileNameWithoutExt(filename string) string { ext := filepath.Ext(filename) return strings.TrimSuffix(filepath.Base(filename), ext) } // IsImageFile 检查是否为图片文件 func IsImageFile(filename string) bool { ext := strings.ToLower(filepath.Ext(filename)) imageExts := []string{".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp", ".svg"} for _, imgExt := range imageExts { if ext == imgExt { return true } } return false } // EnsureDirExists 确保目录存在,不存在则创建 func EnsureDirExists(dirPath string) error { return os.MkdirAll(dirPath, 0755) } // GetAvailableFilename 获取可用的文件名(如果原文件存在则添加序号) func GetAvailableFilename(originalPath string) string { if !CheckFileExists(originalPath) { return originalPath } baseDir := filepath.Dir(originalPath) fileName := filepath.Base(originalPath) ext := filepath.Ext(fileName) nameWithoutExt := strings.TrimSuffix(fileName, ext) counter := 1 for { newPath := filepath.Join(baseDir, fmt.Sprintf("%s_%d%s", nameWithoutExt, counter, ext)) if !CheckFileExists(newPath) { return newPath } counter++ } } // ForceDeleteFile 强制删除文件,即使被占用也尝试删除 func ForceDeleteFile(filePath string) error { // 先尝试正常删除 if err := DeleteFileIfExists(filePath); err == nil { return nil } // 如果正常删除失败,在Windows上可以尝试重命名后删除 if runtime.GOOS == "windows" { // 生成临时文件名 tempPath := GenerateUniqueFileName(filePath) if err := os.Rename(filePath, tempPath); err == nil { // 重命名成功,现在删除临时文件 return os.Remove(tempPath) } } return fmt.Errorf("无法删除文件: %s", filePath) }