diff --git a/hutool-extra/src/main/java/cn/hutool/extra/ftp/Ftp.java b/hutool-extra/src/main/java/cn/hutool/extra/ftp/Ftp.java index 21cc8368b..ee4aab39e 100755 --- a/hutool-extra/src/main/java/cn/hutool/extra/ftp/Ftp.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/ftp/Ftp.java @@ -756,4 +756,5 @@ public class Ftp extends AbstractFtp { this.client = null; } } + } diff --git a/hutool-extra/src/main/java/cn/hutool/extra/ssh/SshjSftp.java b/hutool-extra/src/main/java/cn/hutool/extra/ssh/SshjSftp.java index 9f6c47e3b..227f4e421 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/ssh/SshjSftp.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/ssh/SshjSftp.java @@ -1,6 +1,7 @@ package cn.hutool.extra.ssh; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.StrUtil; @@ -36,6 +37,7 @@ public class SshjSftp extends AbstractFtp { private SSHClient ssh; private SFTPClient sftp; private Session session; + private String workingDir; /** * 构造,使用默认端口 @@ -88,7 +90,7 @@ public class SshjSftp extends AbstractFtp { * @param config FTP配置 * @since 5.3.3 */ - protected SshjSftp(FtpConfig config) { + public SshjSftp(FtpConfig config) { super(config); init(); } @@ -126,34 +128,65 @@ public class SshjSftp extends AbstractFtp { return this; } + private String getPath(String path) { + if (StrUtil.isBlank(this.workingDir)) { + try { + this.workingDir = sftp.canonicalize(""); + } catch (IOException e) { + throw new FtpException(e); + } + } + + if (StrUtil.isBlank(path)) { + return this.workingDir; + } + + // 如果是绝对路径,则返回 + if (StrUtil.startWith(path, StrUtil.SLASH)) { + return path; + } else { + String tmp = StrUtil.removeSuffix(this.workingDir, StrUtil.SLASH); + return StrUtil.format("{}/{}", tmp, path); + } + } + + /** + * 改变目录,注意目前不支持.. + * @param directory directory + * @return true:成功 + */ @Override public boolean cd(String directory) { - String exec = String.format("cd %s", directory); - command(exec); - String pwd = pwd(); - return pwd.equals(directory); + String newPath = getPath(directory); + try { + sftp.ls(newPath); + this.workingDir = newPath; + return true; + } catch (IOException e) { + throw new FtpException(e); + } } @Override public String pwd() { - return command("pwd"); + return getPath(null); } @Override public boolean mkdir(String dir) { try { - sftp.mkdir(dir); + sftp.mkdir(getPath(dir)); } catch (IOException e) { throw new FtpException(e); } - return containsFile(dir); + return containsFile(getPath(dir)); } @Override public List ls(String path) { List infoList; try { - infoList = sftp.ls(path); + infoList = sftp.ls(getPath(path)); } catch (IOException e) { throw new FtpException(e); } @@ -166,8 +199,8 @@ public class SshjSftp extends AbstractFtp { @Override public boolean delFile(String path) { try { - sftp.rm(path); - return !containsFile(path); + sftp.rm(getPath(path)); + return !containsFile(getPath(path)); } catch (IOException e) { throw new FtpException(e); } @@ -176,8 +209,8 @@ public class SshjSftp extends AbstractFtp { @Override public boolean delDir(String dirPath) { try { - sftp.rmdir(dirPath); - return !containsFile(dirPath); + sftp.rmdir(getPath(dirPath)); + return !containsFile(getPath(dirPath)); } catch (IOException e) { throw new FtpException(e); } @@ -186,8 +219,11 @@ public class SshjSftp extends AbstractFtp { @Override public boolean upload(String destPath, File file) { try { - sftp.put(new FileSystemFile(file), destPath); - return containsFile(destPath); + if (StrUtil.endWith(destPath, StrUtil.SLASH)) { + destPath += file.getName(); + } + sftp.put(new FileSystemFile(file), getPath(destPath)); + return containsFile(getPath(destPath)); } catch (IOException e) { throw new FtpException(e); } @@ -196,7 +232,7 @@ public class SshjSftp extends AbstractFtp { @Override public void download(String path, File outFile) { try { - sftp.get(path, new FileSystemFile(outFile)); + sftp.get(getPath(path), new FileSystemFile(outFile)); } catch (IOException e) { throw new FtpException(e); } @@ -204,9 +240,15 @@ public class SshjSftp extends AbstractFtp { @Override public void recursiveDownloadFolder(String sourcePath, File destDir) { - List files = ls(sourcePath); + if (!destDir.exists() || !destDir.isDirectory()) { + if (!destDir.mkdirs()) { + throw new FtpException("创建目录" + destDir.getAbsolutePath() + "失败"); + } + } + + List files = ls(getPath(sourcePath)); if (files != null && !files.isEmpty()) { - files.forEach(path -> download(sourcePath + "/" + path, destDir)); + files.forEach(file -> download(sourcePath + "/" + file, FileUtil.file(destDir, file))); } } @@ -236,7 +278,7 @@ public class SshjSftp extends AbstractFtp { */ public boolean containsFile(String fileDir) { try { - sftp.lstat(fileDir); + sftp.lstat(getPath(fileDir)); return true; } catch (IOException e) { return false; diff --git a/hutool-extra/src/test/java/cn/hutool/extra/ftp/FtpTest.java b/hutool-extra/src/test/java/cn/hutool/extra/ftp/FtpTest.java index 33f392519..84692a4a1 100644 --- a/hutool-extra/src/test/java/cn/hutool/extra/ftp/FtpTest.java +++ b/hutool-extra/src/test/java/cn/hutool/extra/ftp/FtpTest.java @@ -13,6 +13,8 @@ import java.io.File; import java.io.IOException; import java.util.List; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class FtpTest { @Test @@ -171,4 +173,14 @@ public class FtpTest { Console.log(ftp.pwd()); } } + + @Test + public void renameTest() { + final Ftp ftp = new Ftp("localhost", 21, "test", "test"); + + ftp.mkdir("/ftp-1"); + assertTrue(ftp.exist("/ftp-1")); + ftp.rename("/ftp-1", "/ftp-2"); + assertTrue(ftp.exist("/ftp-2")); + } } diff --git a/hutool-extra/src/test/java/cn/hutool/extra/ssh/SftpTest.java b/hutool-extra/src/test/java/cn/hutool/extra/ssh/SftpTest.java index e7429b873..39eaeca3d 100644 --- a/hutool-extra/src/test/java/cn/hutool/extra/ssh/SftpTest.java +++ b/hutool-extra/src/test/java/cn/hutool/extra/ssh/SftpTest.java @@ -2,8 +2,8 @@ package cn.hutool.extra.ssh; import cn.hutool.core.util.CharsetUtil; import org.junit.Before; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Disabled; import java.io.File; import java.util.List; @@ -16,52 +16,66 @@ import java.util.List; */ public class SftpTest { - private SshjSftp sshjSftp; + private Sftp sftp; @Before @Disabled public void init() { - sshjSftp = new SshjSftp("ip", 22, "test", "test", CharsetUtil.CHARSET_UTF_8); + sftp = new Sftp("127.0.0.1", 8022, "test", "test", CharsetUtil.CHARSET_UTF_8); } @Test @Disabled public void lsTest() { - List files = sshjSftp.ls("/"); + List files = sftp.ls("/"); if (files != null && !files.isEmpty()) { - files.forEach(System.out::print); + files.forEach(System.out::println); } } @Test @Disabled public void downloadTest() { - sshjSftp.recursiveDownloadFolder("/home/test/temp", new File("C:\\Users\\akwangl\\Downloads\\temp")); + sftp.recursiveDownloadFolder("/temp/20250427/", new File("D:\\temp\\20250430\\20250427\\")); } @Test @Disabled public void uploadTest() { - sshjSftp.upload("/home/test/temp/", new File("C:\\Users\\akwangl\\Downloads\\temp\\辽宁_20190718_104324.CIME")); + sftp.upload("/ftp-2/20250430/", new File("D:\\temp\\20250430\\test.txt")); } @Test @Disabled public void mkDirTest() { - boolean flag = sshjSftp.mkdir("/home/test/temp"); + boolean flag = sftp.mkdir("/ftp-2/20250430-1"); System.out.println("是否创建成功: " + flag); } + @Test + @Disabled + public void pwdTest() { + String pwd = sftp.pwd(); + System.out.println("PWD: " + pwd); + } + @Test @Disabled public void mkDirsTest() { // 在当前目录下批量创建目录 - sshjSftp.mkDirs("/home/test/temp"); + sftp.mkDirs("/ftp-2/20250430-2/t1/t2/"); } @Test @Disabled public void delDirTest() { - sshjSftp.delDir("/home/test/temp"); + sftp.delDir("/ftp-2/20250430-2/t1/t2"); + } + + @Test + @Disabled + public void cdTest() { + System.out.println(sftp.cd("/ftp-2")); + System.out.println(sftp.cd("/ftp-4")); } } diff --git a/hutool-extra/src/test/java/cn/hutool/extra/ssh/SshjSftpTest.java b/hutool-extra/src/test/java/cn/hutool/extra/ssh/SshjSftpTest.java new file mode 100644 index 000000000..29ff13358 --- /dev/null +++ b/hutool-extra/src/test/java/cn/hutool/extra/ssh/SshjSftpTest.java @@ -0,0 +1,86 @@ +package cn.hutool.extra.ssh; + +import cn.hutool.core.util.CharsetUtil; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * 基于sshj 框架SFTP 封装测试. + * + * @author youyongkun + * @since 5.7.18 + */ +class SshjSftpTest { + + private static SshjSftp sshjSftp; + + @BeforeAll + public static void init() { + sshjSftp = new SshjSftp("localhost", 8022, "test", "test", CharsetUtil.CHARSET_UTF_8); + } + + @Test + @Disabled + public void lsTest() { + List files = sshjSftp.ls("/"); + if (files != null && !files.isEmpty()) { + files.forEach(System.out::println); + } + } + + @Test + @Disabled + public void downloadTest() { + sshjSftp.recursiveDownloadFolder("/home/test/temp", new File("C:\\Users\\akwangl\\Downloads\\temp")); + } + + @Test + @Disabled + public void uploadTest() { + sshjSftp.upload("/home/test/temp/", new File("C:\\Users\\akwangl\\Downloads\\temp\\辽宁_20190718_104324.CIME")); + } + + @Test + @Disabled + public void mkDirTest() { + boolean flag = sshjSftp.mkdir("/home/test/temp"); + System.out.println("是否创建成功: " + flag); + } + + @Test + @Disabled + public void mkDirsTest() { + // 在当前目录下批量创建目录 + sshjSftp.mkDirs("/home/test/temp"); + } + + @Test + @Disabled + public void delDirTest() { + sshjSftp.delDir("/home/test/temp"); + } + + @Test + public void pwdTest() { +// mkDirsTest(); + sshjSftp.cd("/ftp"); + String pwd = sshjSftp.pwd(); + System.out.println("当前目录: " + pwd); + assertEquals("/ftp", pwd); + } + + @Test + public void renameTest() { +// sshjSftp.mkdir("/ftp-1"); + assertTrue(sshjSftp.exist("/ftp-1")); + sshjSftp.rename("/ftp-1", "/ftp-2"); + assertTrue(sshjSftp.exist("/ftp-2")); + } +}