You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用JSch上传文件至SFTP服务器后目标目录无可见文件问题咨询

JSch SFTP上传文件无报错但找不到文件的排查修复方案
  • 问题复现代码

String localFile = "/usr/local/test.pdf";
String remotePath = "/tmp/test.pdf";

JSch jsch = new JSch();
jsch.setKnownHosts("/home/wasadm/.ssh/known_hosts");
jschSession = jsch.getSession(USERNAME, REMOTE_HOST, REMOTE_PORT);
jschSession.setPassword(PASSWORD);
jschSession.connect(SESSION_TIMEOUT);

Channel sftp = jschSession.openChannel("sftp");
sftp.connect(CHANNEL_TIMEOUT);

ChannelSftp channelSftp = (ChannelSftp) sftp;

channelSftp.put(localFile, remotePath);
  • 核心原因及修复方案

    1. SFTP chroot目录隔离
      多数企业级SFTP服务端会对登陆用户配置chroot隔离,你代码中写的绝对路径/tmp/test.pdf,实际对应服务器物理路径为{ChrootDirectory配置的根目录}/tmp/test.pdf,而非系统根目录下的/tmp路径。
      排查方法:连接成功后执行以下代码打印目录信息确认映射关系:
    // 打印当前用户工作目录
    System.out.println("当前工作目录:" + channelSftp.pwd());
    // 打印当前用户根目录下的所有文件
    System.out.println("根目录文件列表:" + channelSftp.ls("/"));
    
    1. 缓冲区未刷入,资源未正常关闭
      你当前代码执行put操作后未主动关闭通道和会话,小文件会滞留在传输缓冲区,连接断开时未完成实际磁盘写入。在put逻辑后补充以下代码即可:
    channelSftp.exit();
    sftp.disconnect();
    jschSession.disconnect();
    
    1. 远程路径冲突
      如果远程已存在名为/tmp/test.pdf的目录,JSch默认会把本地文件上传到该目录下,最终路径为/tmp/test.pdf/test.pdf,导致你在预期目录找不到目标文件。
      修复方法:上传前先校验路径类型:
    try {
        SftpATTRS attrs = channelSftp.lstat(remotePath);
        if (attrs.isDir()) {
            // 存在同名目录,拼接正确的文件路径
            String fileName = localFile.substring(localFile.lastIndexOf("/") + 1);
            remotePath = remotePath + "/" + fileName;
        }
    } catch (SftpException e) {
        // 路径不存在,无需调整
        if (e.id != ChannelSftp.SSH_FX_NO_SUCH_FILE) {
            throw e;
        }
    }
    
    1. 权限校验缺失
      部分SFTP服务端会静默返回写入成功,但实际因用户无目标路径写入权限未完成落盘,可在上传后主动校验文件是否存在:
    try {
        channelSftp.lstat(remotePath);
        System.out.println("文件上传成功,路径:" + remotePath);
    } catch (SftpException e) {
        System.out.println("文件上传失败,无对应路径:" + remotePath);
    }
    
  • 辅助排查手段

如果以上方案都未解决问题,可以开启JSch调试日志查看完整传输链路:

JSch.setLogger(new com.jcraft.jsch.Logger() {
    @Override
    public boolean isEnabled(int level) {
        return true;
    }
    @Override
    public void log(int level, String message) {
        System.out.println("[JSch调试日志] " + message);
    }
});

内容的提问来源于stack exchange,提问作者Madhu Nali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 01:27:02