package send import ( "context" "fmt" "github.com/gogf/gf/v2/frame/g" "github.com/pkg/sftp" "golang.org/x/crypto/ssh" "io" "io/fs" "os" "path/filepath" "time" ) func UpLoadFilesToSftp(ctx context.Context, dir string) (int, []string) { // SFTP 连接配置 var ( config = &ssh.ClientConfig{ User: g.Cfg().MustGet(ctx, "sftp.user").String(), // 替换为你的用户名 Auth: []ssh.AuthMethod{ ssh.Password(g.Cfg().MustGet(ctx, "sftp.pwd").String()), // 替换为你的密码 }, HostKeyCallback: ssh.InsecureIgnoreHostKey(), // 生产环境应使用 ssh.FixedHostKey Timeout: 30 * time.Second, } successNum int failPath []string ) // 使用 fs.WalkDir fs.WalkDir(os.DirFS(dir), ".", func(path string, d fs.DirEntry, err error) error { if err != nil { g.Log().Infof(ctx, "访问路径 %q 失败: %v", path, err) return nil } if !d.IsDir() { // 获取文件信息 info, err := d.Info() if err != nil { g.Log().Infof(ctx, "获取文件信息失败: %v", err) return nil } fullPath := filepath.Join(dir, path) g.Log().Infof(ctx, "文件: %s (大小: %d bytes)", fullPath, info.Size()) // 上传文件 uploadErr := uploadToSFTP(config, g.Cfg().MustGet(ctx, "sftp.addr").String(), fullPath, fullPath) if uploadErr != nil { failPath = append(failPath, fullPath) g.Log().Errorf(ctx, "%s 文件上传失败: %s", fullPath, uploadErr.Error()) } else { successNum++ g.Log().Infof(ctx, "%s 文件上传成功!", fullPath) } } return nil }) return successNum, failPath } // 上传文件到SFTP服务器 func uploadToSFTP(config *ssh.ClientConfig, addr, localPath, remotePath string) error { // 1. 建立SSH连接 sshClient, err := ssh.Dial("tcp", addr, config) if err != nil { return fmt.Errorf("SSH连接失败: %w", err) } defer sshClient.Close() // 2. 创建SFTP客户端 sftpClient, err := sftp.NewClient(sshClient) if err != nil { return fmt.Errorf("创建SFTP客户端失败: %w", err) } defer sftpClient.Close() // 3. 打开本地文件 localFile, err := os.Open(localPath) if err != nil { return fmt.Errorf("打开本地文件失败: %w", err) } defer localFile.Close() // 4. 确保远程目录存在 remoteDir := filepath.Dir(remotePath) if err := sftpClient.MkdirAll(remoteDir); err != nil { return fmt.Errorf("创建远程目录失败: %w", err) } // 5. 创建远程文件 remoteFile, err := sftpClient.Create(remotePath) if err != nil { return fmt.Errorf("创建远程文件失败: %w", err) } defer remoteFile.Close() // 6. 复制文件内容 if _, err := io.Copy(remoteFile, localFile); err != nil { return fmt.Errorf("复制文件内容失败: %w", err) } return nil }