package services import ( "context" "fmt" "os" "os/exec" "path/filepath" "runtime" "strings" ) // FileService 文件服务 type FileService struct{} // NewFileService 创建文件服务实例 func NewFileService() *FileService { return &FileService{} } // SelectFolder 选择文件夹(返回路径) func (s *FileService) SelectFolder(ctx context.Context) (string, error) { LogDebug("开始选择文件夹...") // 根据操作系统使用不同的方法 switch runtime.GOOS { case "darwin": // macOS return s.selectFolderMacOS() case "windows": return s.selectFolderWindows() case "linux": return s.selectFolderLinux() default: return "", fmt.Errorf("不支持的操作系统: %s", runtime.GOOS) } } // selectFolderMacOS 在 macOS 上选择文件夹 func (s *FileService) selectFolderMacOS() (string, error) { // 使用 AppleScript 打开文件夹选择对话框 script := `tell application "System Events" activate set folderPath to choose folder with prompt "请选择文件夹" return POSIX path of folderPath end tell` cmd := exec.Command("osascript", "-e", script) output, err := cmd.Output() if err != nil { LogErrorf("选择文件夹失败: %v", err) return "", fmt.Errorf("选择文件夹失败: %v", err) } path := strings.TrimSpace(string(output)) LogInfof("选择的文件夹路径: %s", path) return path, nil } // selectFolderWindows 在 Windows 上选择文件夹 func (s *FileService) selectFolderWindows() (string, error) { // 使用 PowerShell 打开文件夹选择对话框 script := `Add-Type -AssemblyName System.Windows.Forms $folderBrowser = New-Object System.Windows.Forms.FolderBrowserDialog $folderBrowser.Description = "请选择文件夹" $result = $folderBrowser.ShowDialog() if ($result -eq [System.Windows.Forms.DialogResult]::OK) { Write-Output $folderBrowser.SelectedPath }` cmd := exec.Command("powershell", "-Command", script) output, err := cmd.Output() if err != nil { LogErrorf("选择文件夹失败: %v", err) return "", fmt.Errorf("选择文件夹失败: %v", err) } path := strings.TrimSpace(string(output)) LogInfof("选择的文件夹路径: %s", path) return path, nil } // selectFolderLinux 在 Linux 上选择文件夹 func (s *FileService) selectFolderLinux() (string, error) { // 使用 zenity 或 kdialog 打开文件夹选择对话框 var cmd *exec.Cmd // 先尝试使用 zenity if _, err := exec.LookPath("zenity"); err == nil { cmd = exec.Command("zenity", "--file-selection", "--directory", "--title=请选择文件夹") } else if _, err := exec.LookPath("kdialog"); err == nil { cmd = exec.Command("kdialog", "--getexistingdirectory", "$HOME", "--title", "请选择文件夹") } else { return "", fmt.Errorf("未找到 zenity 或 kdialog,无法打开文件夹选择对话框") } output, err := cmd.Output() if err != nil { LogErrorf("选择文件夹失败: %v", err) return "", fmt.Errorf("选择文件夹失败: %v", err) } path := strings.TrimSpace(string(output)) LogInfof("选择的文件夹路径: %s", path) return path, nil } // SelectFile 选择文件(返回路径) func (s *FileService) SelectFile(ctx context.Context, filter string) (string, error) { // 在 Wails3 中,文件选择需要通过前端实现 return "", nil } // OpenFolder 打开文件夹 func (s *FileService) OpenFolder(ctx context.Context, folderPath string) error { LogDebugf("打开文件夹: %s", folderPath) // 检查文件夹是否存在 if _, err := os.Stat(folderPath); os.IsNotExist(err) { return fmt.Errorf("文件夹不存在: %s", folderPath) } // 根据操作系统使用不同的命令 var cmd *exec.Cmd switch runtime.GOOS { case "darwin": // macOS cmd = exec.Command("open", folderPath) case "windows": cmd = exec.Command("explorer", folderPath) case "linux": cmd = exec.Command("xdg-open", folderPath) default: return fmt.Errorf("不支持的操作系统: %s", runtime.GOOS) } err := cmd.Run() if err != nil { LogErrorf("打开文件夹失败: %v", err) return fmt.Errorf("打开文件夹失败: %v", err) } LogInfo("文件夹已打开") return nil } // FileExists 检查文件是否存在 func (s *FileService) FileExists(ctx context.Context, filePath string) (bool, error) { _, err := os.Stat(filePath) if err == nil { return true, nil } if os.IsNotExist(err) { return false, nil } return false, err } // GetFileSize 获取文件大小(字节) func (s *FileService) GetFileSize(ctx context.Context, filePath string) (int64, error) { info, err := os.Stat(filePath) if err != nil { return 0, err } return info.Size(), nil } // EnsureDirectory 确保目录存在 func (s *FileService) EnsureDirectory(ctx context.Context, dirPath string) error { return os.MkdirAll(dirPath, 0755) } // ListFiles 列出目录中的文件 func (s *FileService) ListFiles(ctx context.Context, dirPath string, pattern string) ([]string, error) { patternPath := filepath.Join(dirPath, pattern) matches, err := filepath.Glob(patternPath) if err != nil { return nil, err } return matches, nil }