147 lines
4.1 KiB
Go
147 lines
4.1 KiB
Go
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
|
||
}
|