package send import ( "context" "fmt" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/frame/g" "github.com/pkg/sftp" "golang.org/x/crypto/ssh" "io" "os" "path/filepath" "strings" "time" ) func UpLoadFilesToSftp(ctx context.Context, fullPath string) error { // 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 ) info, err := os.Stat(fullPath) if err != nil { return gerror.Wrap(err, "读取文件失败") } g.Log().Infof(ctx, "文件: %s (大小: %d bytes)", fullPath, info.Size()) // 上传文件 uploadErr := uploadToSFTP(config, g.Cfg().MustGet(ctx, "sftp.addr").String(), fullPath, strings.Replace(fullPath, "out/", "", 1)) if uploadErr != nil { failPath = append(failPath, fullPath) return gerror.Wrapf(err, "%s 文件上传失败", fullPath) } else { successNum++ g.Log().Infof(ctx, "%s 文件上传成功!", fullPath) } return nil } // 上传文件到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 }