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 逐级创建。

相关推荐
songbaoxian2 分钟前
ElasticSearch
java·linux·elasticsearch
非 白16 分钟前
【Java】代理模式
java·开发语言·代理模式
Good Note27 分钟前
Golang的静态强类型、编译型、并发型
java·数据库·redis·后端·mysql·面试·golang
我就是我3521 小时前
记录一次SpringMVC的406错误
java·后端·springmvc
向哆哆1 小时前
Java应用程序的跨平台性能优化研究
java·开发语言·性能优化
ekkcole2 小时前
windows使用命令解压jar包,替换里面的文件。并重新打包成jar包,解决Failed to get nested archive for entry
java·windows·jar
handsomestWei2 小时前
java实现多图合成mp4和视频附件下载
java·开发语言·音视频·wutool·图片合成视频·视频附件下载
全栈若城2 小时前
03 Python字符串与基础操作详解
java·开发语言·python
伯牙碎琴2 小时前
二、Spring Framework基础:IoC(控制反转)和DI(依赖注入)
java·spring·log4j
菲力蒲LY3 小时前
输入搜索、分组展示选项、下拉选取,全局跳转页,el-select 实现 —— 后端数据处理代码,抛砖引玉展思路
java·前端·mybatis