Java 通过 SFTP 和 FTP 访问时相对路径引发的问题汇总

背景

常用的 Java SSH 操作工具包是 jsch ,FTP 工具包 commons-net ,本文介绍本文总结 Java 程序通过 SFTP 协议和 FTP 协议访问远程文件的过程中,需要注意的路径问题。

本文将解答下面三个问题:

  1. FTPClient 获取当前用户根目录的方法
  2. ChannelSftp 获取当前用户根目录的方法。
  3. 目录切换时,如果是相对目录,可能存在的问题。
  4. 目标目录不存在时,逐级创建目录的方法。

相对路径操作注意事项

jsch 通过 ChannelSftp 访问 SFTP 时,获取当前登录用户根目录的方法有两种:

  1. pwd() 方法
  2. getHome() 方法

两者在刚刚登录成功后返回的值是一样的,都是当前登录用户的 home 目录。 FTPClient 获取当前登录用户的根目录方法为:printWorkingDirectory()

注意:如果操作的目标目录是相对路径,例如目标目录变量名称为 dir,判断绝对路径的方法为:

bash 复制代码
boolean isNotAbsolutePath = !dir.startWith(File.separator);
if (isNotAbsolutePath) {
   String homePath = ftpClient.printWorkingDirectory();
   或 
   String homePath = sftpChannel.pwd();
   
   // 最后拼接上根目录
   dir = homePath + File.separator + dir;
}

修正操作目标路径为绝对路径后,后面的操作就不会报文件不存在错误了。

listFiles 的内容

FTPClient 的 listFiles 文件列表中不包含 ... 这两个特殊的文件,但是使用 jsch 的 ChannelSftp 的 ls 直接列出的文件却包含 ...

所以在遍历文件过程中,对于 Sftp 访问操作,需要排除这两种特殊文件。

相对路径时 ls 或 cd 异常问题

如果使用相对路径,ChannelSftp 的 ls 操作会异常:

java 复制代码
com.jcraft.jsch.SftpException: No such file
	at com.jcraft.jsch.ChannelSftp.throwStatusError(ChannelSftp.java:2873) ~[jsch-0.1.54.jar:?]
	at com.jcraft.jsch.ChannelSftp._stat(ChannelSftp.java:2225) ~[jsch-0.1.54.jar:?]
	at com.jcraft.jsch.ChannelSftp._stat(ChannelSftp.java:2242) ~[jsch-0.1.54.jar:?]
	at com.jcraft.jsch.ChannelSftp.ls(ChannelSftp.java:1592) ~[jsch-0.1.54.jar:?]
	at com.jcraft.jsch.ChannelSftp.ls(ChannelSftp.java:1553) ~[jsch-0.1.54.jar:?]

解决办法,就是第二部分「相对路径操作注意事项」的内容,必须在真正切换目录之前拼接上当前登录用户的根目录。

逐级创建目录的方法

Java 的 FTP 和 SFTP 工具操作是的 mkdir 方法,当父级目录不存在时,直接用目录创建方法会失败,只能逐级创建每个目录。

确实有些场景下需要自动创建一个多层级的新目录,解决办法就是逐级拆解路径,判断当前路径是否存在,如果不存在,就创建,直到到达最后一级。

FTPClient 逐级创建一个目标目录 dirPath 的方法:

bash 复制代码
void createFilePath(FTPClient ftpClient, String filePath) {
    String[] dirPaths = filePath.split("/");
    for (int i = 0; i < dirPaths.length; i++) {
        if (StringUtils.isEmpty(dirPaths[i])) {
            continue;
        }

        StringBuffer buffer = new StringBuffer();
        for (int j = 0; j <= i; j++) {
            buffer.append(dirPaths[j]).append("/");
        }

        String tempDir = buffer.toString();
        try {
            // 切换目录,如果成功,则忽略
            boolean change= ftpClient.changeWorkingDirectory(filePath);
            if (change) {
                continue;
            }

            // 切换失败,则创建
            boolean result = ftpClient.makeDirectory(tempDir);
        } catch (Exception ex) {
            // ERROR
        }
    }
}

ChannelSftp 逐级创建一个目标目录 dirPath 的方法:

bash 复制代码
private boolean createFilePath(ChannelSftp channelSftp, String filePath) {
    String[] dirPaths = filePath.split("/");
    for (int i = 0; i < dirPaths.length; i++) {
        if (StringUtils.isEmpty(dirPaths[i])) {
            continue;
        }

        StringBuffer buffer = new StringBuffer();
        for (int j = 0; j <= i; j++) {
            buffer.append(dirPaths[j]).append("/");
        }

        String tempDir = buffer.toString();
        try {
            channelSftp.mkdir(tempDir);
        } catch (SftpException ex) {
            // ERROR
        }
    }
}

FTPClient 有 changeWorkingDirectory 方法返回一个 boolean 值,可以判断目录是否存在,不存在可以执行创建操作;ChannelSftp 的 cd 没有返回值,所以直接mkdir 逐级创建。

相关推荐
科技块儿6 分钟前
多语言技术栈如何共用IP离线库?Java、Python、Go 的加载实践
java·python·tcp/ip
chools20 分钟前
一篇文章带你搞懂Java“设计模式”! - - 超长文(涵盖23种)万字总结!【汇总篇】
java·开发语言·设计模式
良逍Ai出海21 分钟前
OpenClaw 新手最该先搞懂的 2 套命令
android·java·数据库
6+h29 分钟前
【Spring】深度剖析IoC
java·后端·spring
程序员JerrySUN38 分钟前
别再把 HTTPS 和 OTA 看成两回事:一篇讲透 HTTPS 协议、安全通信机制与 Mender 升级加密链路的完整文章
android·java·开发语言·深度学习·流程图
郝学胜-神的一滴1 小时前
系统设计与面向对象设计:两大设计思想的深度剖析
java·前端·c++·ue5·软件工程
myloveasuka1 小时前
[Java]子类到底能继承父类中的哪些东西?继承中成员变量/方法访问特点---就近原则
java·开发语言
umeelove351 小时前
vscode配置django环境并创建django项目(全图文操作)
java
x-cmd1 小时前
[260307] x-cmd v0.8.6:新增 gpt-5.4 模型支持,sudo/os/hostname/cpu 等模块文档更新
java·数据库·gpt·sudo·x-cmd·googel
PPPPickup1 小时前
深信服公司---java实习生后端一二面询问
java·后端·ai