From a2303b11db39fa3578adc95d7c56d6606bbf02c5 Mon Sep 17 00:00:00 2001 From: chenzz Date: Mon, 11 May 2020 11:09:01 +0800 Subject: [PATCH] =?UTF-8?q?add:=20=E9=80=92=E5=BD=92=E4=B8=8B=E8=BD=BDFTP?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=99=A8=E4=B8=8A=E6=96=87=E4=BB=B6=E5=88=B0?= =?UTF-8?q?=E6=9C=AC=E5=9C=B0(=E6=94=AF=E6=8C=81=E6=99=AE=E9=80=9Aftp?= =?UTF-8?q?=E5=92=8Csftp)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/hutool/extra/ftp/AbstractFtp.java | 8 ++ .../main/java/cn/hutool/extra/ftp/Ftp.java | 29 +++++++ .../main/java/cn/hutool/extra/ssh/Sftp.java | 84 +++++++++++++------ .../java/cn/hutool/extra/ftp/FtpTest.java | 22 +++++ 4 files changed, 117 insertions(+), 26 deletions(-) diff --git a/hutool-extra/src/main/java/cn/hutool/extra/ftp/AbstractFtp.java b/hutool-extra/src/main/java/cn/hutool/extra/ftp/AbstractFtp.java index 6b8397557..3e21149a4 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/ftp/AbstractFtp.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/ftp/AbstractFtp.java @@ -154,6 +154,14 @@ public abstract class AbstractFtp implements Closeable { */ public abstract void download(String path, File outFile); + /** + * 递归下载FTP服务器上文件到本地(文件目录和服务器同步), 服务器上有新文件会覆盖本地文件 + * + * @param sourcePath ftp服务器目录 + * @param destinationPath 本地目录 + */ + public abstract void recursiveDownloadFolder(String sourcePath, String destinationPath) throws Exception; + // ---------------------------------------------------------------------------------------------------------------------------------------- Private method start /** * 是否包含指定字符串,忽略大小写 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 3cdb4d991..ed7b7841e 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/ftp/Ftp.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/ftp/Ftp.java @@ -476,6 +476,35 @@ public class Ftp extends AbstractFtp { download(dir, fileName, outFile); } + /** + * 递归下载FTP服务器上文件到本地(文件目录和服务器同步) + * + * @param sourcePath ftp服务器目录 + * @param destinationPath 本地目录 + */ + @Override + public void recursiveDownloadFolder(String sourcePath, String destinationPath) { + String pathSeparator = "/"; + FTPFile[] lsFiles = lsFiles(sourcePath); + + for (FTPFile ftpFile : lsFiles) { + String sourcePathPathFile = sourcePath + pathSeparator + ftpFile.getName(); + String destinationPathFile = destinationPath + pathSeparator + ftpFile.getName(); + + if (!ftpFile.isDirectory()) { + // 本地不存在文件或者ftp上文件有修改则下载 + if (!FileUtil.exist(destinationPathFile) + || (ftpFile.getTimestamp().getTimeInMillis() > FileUtil.lastModifiedTime(destinationPathFile).getTime())) { + // Download file from source (source filename, destination filename). + download(sourcePathPathFile, FileUtil.file(destinationPathFile)); + } + } else if (!(".".equals(ftpFile.getName()) || "..".equals(ftpFile.getName()))) { + FileUtil.mkdir(destinationPathFile); + recursiveDownloadFolder(sourcePathPathFile, destinationPathFile); + } + } + } + /** * 下载文件 * diff --git a/hutool-extra/src/main/java/cn/hutool/extra/ssh/Sftp.java b/hutool-extra/src/main/java/cn/hutool/extra/ssh/Sftp.java index d63ea63f9..5ed1f8f63 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/ssh/Sftp.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/ssh/Sftp.java @@ -22,12 +22,12 @@ import java.util.Vector; * SFTP是Secure File Transfer Protocol的缩写,安全文件传送协议。可以为传输文件提供一种安全的加密方法。
* SFTP 为 SSH的一部份,是一种传输文件到服务器的安全方式。SFTP是使用加密传输认证信息和传输的数据,所以,使用SFTP是非常安全的。
* 但是,由于这种传输方式使用了加密/解密技术,所以传输效率比普通的FTP要低得多,如果您对网络安全性要求更高时,可以使用SFTP代替FTP。
- * + * *

* 此类为基于jsch的SFTP实现
* 参考:https://www.cnblogs.com/longyg/archive/2012/06/25/2556576.html *

- * + * * @author looly * @since 4.0.2 */ @@ -39,7 +39,7 @@ public class Sftp extends AbstractFtp { // ---------------------------------------------------------------------------------------- Constructor start /** * 构造 - * + * * @param sshHost 远程主机 * @param sshPort 远程主机端口 * @param sshUser 远程主机用户名 @@ -51,7 +51,7 @@ public class Sftp extends AbstractFtp { /** * 构造 - * + * * @param sshHost 远程主机 * @param sshPort 远程主机端口 * @param sshUser 远程主机用户名 @@ -76,7 +76,7 @@ public class Sftp extends AbstractFtp { /** * 构造 - * + * * @param session {@link Session} */ public Sftp(Session session) { @@ -85,7 +85,7 @@ public class Sftp extends AbstractFtp { /** * 构造 - * + * * @param session {@link Session} * @param charset 编码 * @since 4.1.14 @@ -97,7 +97,7 @@ public class Sftp extends AbstractFtp { /** * 构造 - * + * * @param channel {@link ChannelSftp} * @param charset 编码 */ @@ -109,7 +109,7 @@ public class Sftp extends AbstractFtp { /** * 构造 - * + * * @param sshHost 远程主机 * @param sshPort 远程主机端口 * @param sshUser 远程主机用户名 @@ -141,7 +141,7 @@ public class Sftp extends AbstractFtp { /** * 初始化 - * + * * @param session {@link Session} * @param charset 编码 */ @@ -152,7 +152,7 @@ public class Sftp extends AbstractFtp { /** * 初始化 - * + * * @param channel {@link ChannelSftp} * @param charset 编码 */ @@ -176,7 +176,7 @@ public class Sftp extends AbstractFtp { /** * 获取SFTP通道客户端 - * + * * @return 通道客户端 * @since 4.1.14 */ @@ -186,7 +186,7 @@ public class Sftp extends AbstractFtp { /** * 远程当前目录 - * + * * @return 远程当前目录 */ @Override @@ -200,7 +200,7 @@ public class Sftp extends AbstractFtp { /** * 获取HOME路径 - * + * * @return HOME路径 * @since 4.0.5 */ @@ -214,7 +214,7 @@ public class Sftp extends AbstractFtp { /** * 遍历某个目录下所有文件或目录,不会递归遍历 - * + * * @param path 遍历某个目录下所有文件或目录 * @return 目录或文件名列表 * @since 4.0.5 @@ -226,7 +226,7 @@ public class Sftp extends AbstractFtp { /** * 遍历某个目录下所有目录,不会递归遍历 - * + * * @param path 遍历某个目录下所有目录 * @return 目录名列表 * @since 4.0.5 @@ -237,7 +237,7 @@ public class Sftp extends AbstractFtp { /** * 遍历某个目录下所有文件,不会递归遍历 - * + * * @param path 遍历某个目录下所有文件 * @return 文件名列表 * @since 4.0.5 @@ -248,7 +248,7 @@ public class Sftp extends AbstractFtp { /** * 遍历某个目录下所有文件或目录,不会递归遍历 - * + * * @param path 遍历某个目录下所有文件或目录 * @param filter 文件或目录过滤器,可以实现过滤器返回自己需要的文件或目录名列表 * @return 目录或文件名列表 @@ -287,7 +287,7 @@ public class Sftp extends AbstractFtp { /** * 打开指定目录,如果指定路径非目录或不存在返回false - * + * * @param directory directory * @return 是否打开目录 */ @@ -307,7 +307,7 @@ public class Sftp extends AbstractFtp { /** * 删除文件 - * + * * @param filePath 要删除的文件绝对路径 */ @Override @@ -322,7 +322,7 @@ public class Sftp extends AbstractFtp { /** * 删除文件夹及其文件夹下的所有文件 - * + * * @param dirPath 文件夹路径 * @return boolean 是否删除成功 */ @@ -373,7 +373,7 @@ public class Sftp extends AbstractFtp { /** * 将本地文件上传到目标服务器,目标文件名为destPath,若destPath为目录,则目标文件名将与srcFilePath文件名相同。覆盖模式 - * + * * @param srcFilePath 本地文件路径 * @param destPath 目标路径, * @return this @@ -384,7 +384,7 @@ public class Sftp extends AbstractFtp { /** * 将本地文件上传到目标服务器,目标文件名为destPath,若destPath为目录,则目标文件名将与srcFilePath文件名相同。 - * + * * @param srcFilePath 本地文件路径 * @param destPath 目标路径, * @param mode {@link Mode} 模式 @@ -393,10 +393,10 @@ public class Sftp extends AbstractFtp { public Sftp put(String srcFilePath, String destPath, Mode mode) { return put(srcFilePath, destPath, null, mode); } - + /** * 将本地文件上传到目标服务器,目标文件名为destPath,若destPath为目录,则目标文件名将与srcFilePath文件名相同。 - * + * * @param srcFilePath 本地文件路径 * @param destPath 目标路径, * @param monitor 上传进度监控,通过实现此接口完成进度显示 @@ -418,9 +418,41 @@ public class Sftp extends AbstractFtp { get(src, FileUtil.getAbsolutePath(destFile)); } + /** + * 递归下载FTP服务器上文件到本地(文件目录和服务器同步) + * + * @param sourcePath ftp服务器目录 + * @param destinationPath 本地目录 + */ + @Override + public void recursiveDownloadFolder(String sourcePath, String destinationPath) throws Exception { + String pathSeparator = "/"; + Vector fileAndFolderList = channel.ls(sourcePath); + + //Iterate through list of folder content + for (ChannelSftp.LsEntry item : fileAndFolderList) { + + String sourcePathPathFile = sourcePath + pathSeparator + item.getFilename(); + String destinationPathFile = destinationPath + pathSeparator + item.getFilename(); + + if (!item.getAttrs().isDir()) { + // 本地不存在文件或者ftp上文件有修改则下载 + if (!FileUtil.exist(destinationPathFile) + || (item.getAttrs().getMTime() > (FileUtil.lastModifiedTime(destinationPathFile).getTime() / 1000))) { + // Download file from source (source filename, destination filename). + channel.get(sourcePathPathFile, destinationPathFile); + } + } else if (!(".".equals(item.getFilename()) || "..".equals(item.getFilename()))) { + FileUtil.mkdir(destinationPathFile); + recursiveDownloadFolder(sourcePathPathFile, destinationPathFile); + } + } + + } + /** * 获取远程文件 - * + * * @param src 远程文件路径 * @param dest 目标文件路径 * @return this @@ -451,7 +483,7 @@ public class Sftp extends AbstractFtp { /** * JSch支持的三种文件传输模式 - * + * * @author looly * */ 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 ede110773..f2609ebe3 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 @@ -2,6 +2,7 @@ package cn.hutool.extra.ftp; import java.util.List; +import cn.hutool.extra.ssh.Sftp; import org.junit.Ignore; import org.junit.Test; @@ -59,4 +60,25 @@ public class FtpTest { IoUtil.close(ftp); } + + @Test + @Ignore + public void recursiveDownloadFolder() throws Exception { + Ftp ftp = new Ftp("looly.centos"); + ftp.recursiveDownloadFolder("/","d:/test/download"); + + IoUtil.close(ftp); + } + + @Test + @Ignore + public void recursiveDownloadFolderSftp() throws Exception { + Sftp ftp = new Sftp("127.0.0.1", 22, "test", "test"); + + ftp.cd("/file/aaa"); + Console.log(ftp.pwd()); + ftp.recursiveDownloadFolder("/","d:/test/download"); + + IoUtil.close(ftp); + } }