Go语言SFTP上传无报错但文件未落地问题求助
我来帮你梳理排查这个问题!你遇到的这种「代码执行无报错,但服务器上找不到文件」的情况,大多是一些容易被忽略的细节问题,咱们逐个排查:
1. 优先检查:远程文件流未正确关闭/刷新
看你的两段代码,都没有在创建remoteFile后添加defer remoteFile.Close()!io.Copy完成后,文件数据可能还停留在客户端或服务器的缓冲区里,没有真正写入磁盘。SFTP服务器不会主动帮你刷新缓冲区,必须手动关闭文件句柄或调用同步方法。
修改你的Upload函数,加上文件关闭和同步:
func (c *Client) Upload(local, remote string) error { client, err := sftp.NewClient(c.SSHClient) if err != nil { return err } defer client.Close() localFile, err := os.Open(local) if err != nil { return err } defer localFile.Close() remoteFile, err := client.Create(remote) if err != nil { return err } defer remoteFile.Close() // 必须加上这句,确保文件句柄被关闭 // 写入文件 writtenBytes, err := io.Copy(remoteFile, localFile) if err != nil { return err } // 可选但建议:强制将缓冲区数据刷入磁盘 if err := remoteFile.Sync(); err != nil { return err } // 调试用:打印写入字节数,确认和本地文件大小一致 fmt.Printf("Successfully wrote %d bytes to remote\n", writtenBytes) return nil }
你的Consftp函数也需要做同样的修改,给remoteFile加上defer remoteFile.Close()。这应该是最可能解决问题的点!
2. 确认远程路径是否正确
SFTP客户端连接后的默认工作目录可能和你命令行登录的不一样!比如你命令行登录后默认在/home/your_username,但Go的SFTP客户端可能默认在根目录/,导致你指定的相对路径upload/uuuuu.zip实际指向了/upload/uuuuu.zip,而不是你预期的目录。
可以在代码里先打印当前工作目录,确认路径:
client, err := sftp.NewClient(c.SSHClient) if err != nil { return err } defer client.Close() // 打印当前工作目录 wd, err := client.Getwd() if err != nil { fmt.Println("Failed to get working dir:", err) } else { fmt.Println("Current SFTP working dir:", wd) }
建议直接使用绝对路径上传文件,比如/home/your_username/upload/uuuuu.zip,避免相对路径带来的歧义。
3. 检查SSH用户与权限匹配
虽然命令行能正常上传,但要确认Go代码中使用的SSH用户和你命令行登录的是同一个用户。如果用户不同,可能存在:
- 不同的默认工作目录
- 不同的文件写入权限(比如目标目录对Go代码的用户不可写,但命令行用户可写)
- 服务器端的chroot限制(比如SFTP用户被限定在特定子目录,超出范围的写入会被静默丢弃)
4. 增加调试日志定位问题
在代码中添加更多调试信息,帮助你确认上传过程的细节:
// 检查本地文件是否存在并打印大小 localFile, err := os.Open(local) if err != nil { return err } defer localFile.Close() fi, err := localFile.Stat() if err != nil { return err } fmt.Println("Local file size:", fi.Size()) // 上传后检查远程文件是否存在 if _, err := client.Stat(remote); err != nil { fmt.Println("Remote file not found after upload:", err) } else { fmt.Println("Remote file exists!") }
5. 考虑库版本兼容性问题
你使用的Go版本是go1.10.2,属于比较旧的版本。对应的sftp库(github.com/pkg/sftp)如果也是旧版本,可能存在一些已知的缓冲区刷新或路径处理bug。可以尝试升级到兼容Go1.10的最新sftp库版本,或者查看该库的issue列表,有没有类似的问题记录。
内容的提问来源于stack exchange,提问作者medtrib

