Files
voidraft/internal/services/file_service.go

147 lines
4.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 services
import (
"encoding/json"
"fmt"
"log"
"os"
"path/filepath"
"sync"
)
// FileService 提供原子化文件操作
type FileService struct {
mutex sync.Mutex
}
// NewFileService 创建新的文件服务实例
func NewFileService() *FileService {
return &FileService{}
}
// EnsureDir 确保目录存在,如不存在则创建
func (fs *FileService) EnsureDir(dirPath string) error {
fs.mutex.Lock()
defer fs.mutex.Unlock()
return fs.ensureDirNoLock(dirPath)
}
// ensureDirNoLock 无锁版本的EnsureDir仅供内部使用
func (fs *FileService) ensureDirNoLock(dirPath string) error {
log.Printf("EnsureDir: Checking directory: %s", dirPath)
if _, err := os.Stat(dirPath); os.IsNotExist(err) {
log.Printf("EnsureDir: Directory does not exist, creating: %s", dirPath)
err := os.MkdirAll(dirPath, 0755)
if err != nil {
log.Printf("EnsureDir: Failed to create directory: %v", err)
return err
}
log.Printf("EnsureDir: Directory created successfully: %s", dirPath)
} else {
log.Printf("EnsureDir: Directory already exists: %s", dirPath)
}
return nil
}
// SaveJSON 原子化保存JSON数据到文件
func (fs *FileService) SaveJSON(filePath string, data interface{}) error {
fs.mutex.Lock()
defer fs.mutex.Unlock()
log.Printf("SaveJSON: Saving to file: %s", filePath)
// 确保目录存在 - 使用无锁版本以避免死锁
dir := filepath.Dir(filePath)
if err := fs.ensureDirNoLock(dir); err != nil {
log.Printf("SaveJSON: Failed to create directory: %v", err)
return fmt.Errorf("failed to create directory: %w", err)
}
// 将数据编码为JSON
jsonData, err := json.MarshalIndent(data, "", " ")
if err != nil {
log.Printf("SaveJSON: Failed to encode JSON: %v", err)
return fmt.Errorf("failed to encode JSON: %w", err)
}
// 先写入临时文件
tempFile := filePath + ".tmp"
log.Printf("SaveJSON: Writing to temporary file: %s", tempFile)
if err := os.WriteFile(tempFile, jsonData, 0644); err != nil {
log.Printf("SaveJSON: Failed to write temporary file: %v", err)
return fmt.Errorf("failed to write temporary file: %w", err)
}
// 原子替换原文件
log.Printf("SaveJSON: Replacing original file with temporary file")
if err := os.Rename(tempFile, filePath); err != nil {
os.Remove(tempFile) // 清理临时文件
log.Printf("SaveJSON: Failed to replace file: %v", err)
return fmt.Errorf("failed to replace file: %w", err)
}
log.Printf("SaveJSON: File saved successfully: %s", filePath)
return nil
}
// LoadJSON 从文件加载JSON数据
func (fs *FileService) LoadJSON(filePath string, target interface{}) error {
fs.mutex.Lock()
defer fs.mutex.Unlock()
log.Printf("LoadJSON: Loading from file: %s", filePath)
// 检查文件是否存在
if _, err := os.Stat(filePath); os.IsNotExist(err) {
log.Printf("LoadJSON: File does not exist: %s", filePath)
return fmt.Errorf("file does not exist: %w", err)
}
// 读取文件内容
data, err := os.ReadFile(filePath)
if err != nil {
log.Printf("LoadJSON: Failed to read file: %v", err)
return fmt.Errorf("failed to read file: %w", err)
}
// 解析JSON数据
if err := json.Unmarshal(data, target); err != nil {
log.Printf("LoadJSON: Failed to parse JSON: %v", err)
return fmt.Errorf("failed to parse JSON: %w", err)
}
log.Printf("LoadJSON: File loaded successfully: %s", filePath)
return nil
}
// FileExists 检查文件是否存在
func (fs *FileService) FileExists(filePath string) bool {
_, err := os.Stat(filePath)
exists := !os.IsNotExist(err)
log.Printf("FileExists: Checking if file exists: %s, exists: %v", filePath, exists)
return exists
}
// DeleteFile 删除文件
func (fs *FileService) DeleteFile(filePath string) error {
fs.mutex.Lock()
defer fs.mutex.Unlock()
log.Printf("DeleteFile: Deleting file: %s", filePath)
if !fs.FileExists(filePath) {
log.Printf("DeleteFile: File does not exist, nothing to delete: %s", filePath)
return nil // 文件不存在视为删除成功
}
err := os.Remove(filePath)
if err != nil {
log.Printf("DeleteFile: Failed to delete file: %v", err)
} else {
log.Printf("DeleteFile: File deleted successfully: %s", filePath)
}
return err
}