Files
qiweimanager-master/helper/file_utils.go

286 lines
7.1 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 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)
}