dirs = new ArrayList<>(files.length);
+ //第一次只处理文件,防止目录在前面导致先处理子目录,而引发文件所在目录不正确
+ for (final File f : files) {
+ if (f.isDirectory()) {
+ dirs.add(f);
+ } else {
+ this.uploadFile(remotePath, f);
+ }
+ }
+ //第二次只处理目录
+ for (final File f : dirs) {
+ final String dir = FileUtil.normalize(remotePath + "/" + f.getName());
+ upload(dir, f);
+ }
+ }
+
+ /**
+ * 下载文件
+ *
+ * @param path 文件路径,包含文件名
+ * @param outFile 输出文件或目录,当为目录时,使用服务端的文件名
+ */
+ @Override
+ public void download(final String path, final File outFile) {
+ final String fileName = FileNameUtil.getName(path);
+ final String dir = StrUtil.removeSuffix(path, fileName);
+ download(dir, fileName, outFile);
+ }
+
+ /**
+ * 递归下载FTP服务器上文件到本地(文件目录和服务器同步)
+ *
+ * @param sourcePath ftp服务器目录
+ * @param destDir 本地目录
+ */
+ @Override
+ public void recursiveDownloadFolder(final String sourcePath, final File destDir) {
+ String fileName;
+ String srcFile;
+ File destFile;
+ for (final FTPFile ftpFile : lsFiles(sourcePath, null)) {
+ fileName = ftpFile.getName();
+ srcFile = StrUtil.format("{}/{}", sourcePath, fileName);
+ destFile = FileUtil.file(destDir, fileName);
+
+ if (!ftpFile.isDirectory()) {
+ // 本地不存在文件或者ftp上文件有修改则下载
+ if (!FileUtil.exists(destFile)
+ || (ftpFile.getTimestamp().getTimeInMillis() > destFile.lastModified())) {
+ download(srcFile, destFile);
+ }
+ } else {
+ // 服务端依旧是目录,继续递归
+ FileUtil.mkdir(destFile);
+ recursiveDownloadFolder(srcFile, destFile);
+ }
+ }
+ }
+
+ /**
+ * 下载文件
+ *
+ * @param path 文件所在路径(远程目录),不包含文件名
+ * @param fileName 文件名
+ * @param outFile 输出文件或目录,当为目录时使用服务端文件名
+ * @throws IORuntimeException IO异常
+ */
+ public void download(final String path, final String fileName, File outFile) throws IORuntimeException {
+ if (outFile.isDirectory()) {
+ outFile = new File(outFile, fileName);
+ }
+ if (!outFile.exists()) {
+ FileUtil.touch(outFile);
+ }
+ try (final OutputStream out = FileUtil.getOutputStream(outFile)) {
+ download(path, fileName, out);
+ } catch (final IOException e) {
+ throw new IORuntimeException(e);
+ }
+ }
+
+ /**
+ * 下载文件到输出流
+ *
+ * @param path 文件路径
+ * @param fileName 文件名
+ * @param out 输出位置
+ */
+ public void download(final String path, final String fileName, final OutputStream out) {
+ download(path, fileName, out, null);
+ }
+
+ /**
+ * 下载文件到输出流
+ *
+ * @param path 服务端的文件路径
+ * @param fileName 服务端的文件名
+ * @param out 输出流,下载的文件写出到这个流中
+ * @param fileNameCharset 文件名编码,通过此编码转换文件名编码为ISO8859-1
+ * @throws IORuntimeException IO异常
+ * @since 5.5.7
+ */
+ public void download(final String path, String fileName, final OutputStream out, final Charset fileNameCharset) throws IORuntimeException {
+ String pwd = null;
+ if (this.backToPwd) {
+ pwd = pwd();
+ }
+
+ if (!cd(path)) {
+ throw new FtpException("Change dir to [{}] error, maybe dir not exist!", path);
+ }
+
+ if (null != fileNameCharset) {
+ fileName = new String(fileName.getBytes(fileNameCharset), StandardCharsets.ISO_8859_1);
+ }
+ try {
+ client.setFileType(FTPClient.BINARY_FILE_TYPE);
+ client.retrieveFile(fileName, out);
+ } catch (final IOException e) {
+ throw new IORuntimeException(e);
+ } finally {
+ if (backToPwd) {
+ cd(pwd);
+ }
+ }
+ }
+
+ /**
+ * 获取FTPClient客户端对象
+ *
+ * @return {@link FTPClient}
+ */
+ public FTPClient getClient() {
+ return this.client;
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (null != this.client) {
+ this.client.logout();
+ if (this.client.isConnected()) {
+ this.client.disconnect();
+ }
+ this.client = null;
+ }
+ }
+}
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/ftp/Ftp.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/ftp/Ftp.java
index 3bc8a72e5..514c4820d 100644
--- a/hutool-extra/src/main/java/org/dromara/hutool/extra/ftp/Ftp.java
+++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/ftp/Ftp.java
@@ -1,773 +1,156 @@
-/*
- * Copyright (c) 2023 looly(loolly@aliyun.com)
- * Hutool is licensed under Mulan PSL v2.
- * You can use this software according to the terms and conditions of the Mulan PSL v2.
- * You may obtain a copy of Mulan PSL v2 at:
- * https://license.coscl.org.cn/MulanPSL2
- * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
- * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
- * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
- * See the Mulan PSL v2 for more details.
- */
-
package org.dromara.hutool.extra.ftp;
-import org.dromara.hutool.core.collection.CollUtil;
-import org.dromara.hutool.core.collection.ListUtil;
-import org.dromara.hutool.core.io.file.FileUtil;
-import org.dromara.hutool.core.io.IORuntimeException;
-import org.dromara.hutool.core.io.file.FileNameUtil;
-import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.text.StrUtil;
-import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.util.CharsetUtil;
-import org.apache.commons.net.ftp.FTPClient;
-import org.apache.commons.net.ftp.FTPClientConfig;
-import org.apache.commons.net.ftp.FTPFile;
-import org.apache.commons.net.ftp.FTPReply;
+import org.rythmengine.utils.F;
+import java.io.Closeable;
import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
import java.util.List;
-import java.util.function.Predicate;
/**
- * FTP客户端封装
- * 此客户端基于Apache-Commons-Net
- *
- * 常见搭建ftp的工具有
- * 1、filezila server ;根目录一般都是空
- * 2、linux vsftpd ; 使用的 系统用户的目录,这里往往都是不是根目录,如:/home/ftpuser/ftp
+ * FTP的统一规范接口
*
- * @author looly
- * @since 4.1.8
+ * @author Looly
*/
-public class Ftp extends AbstractFtp {
+public interface Ftp extends Closeable {
/**
- * 默认端口
+ * 默认编码
*/
- public static final int DEFAULT_PORT = 21;
-
- private FTPClient client;
- private FtpMode mode;
- /**
- * 执行完操作是否返回当前目录
- */
- private boolean backToPwd;
+ Charset DEFAULT_CHARSET = CharsetUtil.UTF_8;
/**
- * 构造,匿名登录
+ * 获取FTP配置
*
- * @param host 域名或IP
+ * @return FTP配置
*/
- public Ftp(final String host) {
- this(host, DEFAULT_PORT);
- }
+ FtpConfig getConfig();
/**
- * 构造,匿名登录
- *
- * @param host 域名或IP
- * @param port 端口
- */
- public Ftp(final String host, final int port) {
- this(host, port, "anonymous", "");
- }
-
- /**
- * 构造
- *
- * @param host 域名或IP
- * @param port 端口
- * @param user 用户名
- * @param password 密码
- */
- public Ftp(final String host, final int port, final String user, final String password) {
- this(host, port, user, password, CharsetUtil.UTF_8);
- }
-
- /**
- * 构造
- *
- * @param host 域名或IP
- * @param port 端口
- * @param user 用户名
- * @param password 密码
- * @param charset 编码
- */
- public Ftp(final String host, final int port, final String user, final String password, final Charset charset) {
- this(host, port, user, password, charset, null, null);
- }
-
- /**
- * 构造
- *
- * @param host 域名或IP
- * @param port 端口
- * @param user 用户名
- * @param password 密码
- * @param charset 编码
- * @param serverLanguageCode 服务器语言 例如:zh
- * @param systemKey 服务器标识 例如:org.apache.commons.net.ftp.FTPClientConfig.SYST_NT
- */
- public Ftp(final String host, final int port, final String user, final String password, final Charset charset, final String serverLanguageCode, final String systemKey) {
- this(host, port, user, password, charset, serverLanguageCode, systemKey, null);
- }
-
- /**
- * 构造
- *
- * @param host 域名或IP
- * @param port 端口
- * @param user 用户名
- * @param password 密码
- * @param charset 编码
- * @param serverLanguageCode 服务器语言
- * @param systemKey 系统关键字
- * @param mode 模式
- */
- public Ftp(final String host, final int port, final String user, final String password, final Charset charset, final String serverLanguageCode, final String systemKey, final FtpMode mode) {
- this(new FtpConfig(host, port, user, password, charset, serverLanguageCode, systemKey), mode);
- }
-
- /**
- * 构造
- *
- * @param config FTP配置
- * @param mode 模式
- */
- public Ftp(final FtpConfig config, final FtpMode mode) {
- super(config);
- this.mode = mode;
- this.init();
- }
-
- /**
- * 构造
- *
- * @param client 自定义实例化好的{@link FTPClient}
- * @since 5.7.22
- */
- public Ftp(final FTPClient client) {
- super(FtpConfig.of());
- this.client = client;
- }
-
- /**
- * 初始化连接
+ * 如果连接超时的话,重新进行连接
*
* @return this
*/
- public Ftp init() {
- return this.init(this.ftpConfig, this.mode);
- }
+ Ftp reconnectIfTimeout();
/**
- * 初始化连接
- *
- * @param host 域名或IP
- * @param port 端口
- * @param user 用户名
- * @param password 密码
- * @return this
- */
- public Ftp init(final String host, final int port, final String user, final String password) {
- return this.init(host, port, user, password, null);
- }
-
- /**
- * 初始化连接
- *
- * @param host 域名或IP
- * @param port 端口
- * @param user 用户名
- * @param password 密码
- * @param mode 模式
- * @return this
- */
- public Ftp init(final String host, final int port, final String user, final String password, final FtpMode mode) {
- return init(new FtpConfig(host, port, user, password, this.ftpConfig.getCharset(), null, null), mode);
- }
-
- /**
- * 初始化连接
- *
- * @param config FTP配置
- * @param mode 模式
- * @return this
- */
- public Ftp init(final FtpConfig config, final FtpMode mode) {
- final FTPClient client = new FTPClient();
- // issue#I3O81Y@Gitee
- client.setRemoteVerificationEnabled(false);
-
- final Charset charset = config.getCharset();
- if (null != charset) {
- client.setControlEncoding(charset.toString());
- }
- client.setConnectTimeout((int) config.getConnectionTimeout());
- final String systemKey = config.getSystemKey();
- if (StrUtil.isNotBlank(systemKey)) {
- final FTPClientConfig conf = new FTPClientConfig(systemKey);
- final String serverLanguageCode = config.getServerLanguageCode();
- if (StrUtil.isNotBlank(serverLanguageCode)) {
- conf.setServerLanguageCode(config.getServerLanguageCode());
- }
- client.configure(conf);
- }
-
- // connect
- try {
- // 连接ftp服务器
- client.connect(config.getHost(), config.getPort());
- client.setSoTimeout((int) config.getSoTimeout());
- // 登录ftp服务器
- client.login(config.getUser(), config.getPassword());
- } catch (final IOException e) {
- throw new IORuntimeException(e);
- }
- final int replyCode = client.getReplyCode(); // 是否成功登录服务器
- if (!FTPReply.isPositiveCompletion(replyCode)) {
- try {
- client.disconnect();
- } catch (final IOException e) {
- // ignore
- }
- throw new FtpException("Login failed for user [{}], reply code is: [{}]", config.getUser(), replyCode);
- }
- this.client = client;
- if (mode != null) {
- //noinspection resource
- setMode(mode);
- }
- return this;
- }
-
- /**
- * 设置FTP连接模式,可选主动和被动模式
- *
- * @param mode 模式枚举
- * @return this
- * @since 4.1.19
- */
- public Ftp setMode(final FtpMode mode) {
- this.mode = mode;
- switch (mode) {
- case Active:
- this.client.enterLocalActiveMode();
- break;
- case Passive:
- this.client.enterLocalPassiveMode();
- break;
- }
- return this;
- }
-
- /**
- * 设置执行完操作是否返回当前目录
- *
- * @param backToPwd 执行完操作是否返回当前目录
- * @return this
- * @since 4.6.0
- */
- public Ftp setBackToPwd(final boolean backToPwd) {
- this.backToPwd = backToPwd;
- return this;
- }
-
- /**
- * 是否执行完操作返回当前目录
- *
- * @return 执行完操作是否返回当前目录
- * @since 5.7.17
- */
- public boolean isBackToPwd() {
- return this.backToPwd;
- }
-
- /**
- * 如果连接超时的话,重新进行连接 经测试,当连接超时时,client.isConnected()仍然返回ture,无法判断是否连接超时 因此,通过发送pwd命令的方式,检查连接是否超时
- *
- * @return this
- */
- @Override
- public Ftp reconnectIfTimeout() {
- String pwd = null;
- try {
- pwd = pwd();
- } catch (final IORuntimeException fex) {
- // ignore
- }
-
- if (pwd == null) {
- return this.init();
- }
- return this;
- }
-
- /**
- * 改变目录
- *
- * @param directory 目录
- * @return 是否成功
- */
- @Override
- synchronized public boolean cd(final String directory) {
- if (StrUtil.isBlank(directory)) {
- // 当前目录
- return true;
- }
-
- try {
- return client.changeWorkingDirectory(directory);
- } catch (final IOException e) {
- throw new IORuntimeException(e);
- }
- }
-
- /**
- * 远程当前目录
+ * 远程当前目录(工作目录)
*
* @return 远程当前目录
- * @since 4.1.14
*/
- @Override
- public String pwd() {
+ String pwd();
+
+ /**
+ * 打开指定目录,具体逻辑取决于实现,例如在FTP中,进入失败返回{@code false}, SFTP中则抛出异常
+ *
+ * @param directory directory
+ * @return 是否打开目录
+ */
+ boolean cd(String directory);
+
+ /**
+ * 打开上级目录
+ *
+ * @return 是否打开目录
+ */
+ default boolean toParent() {
+ return cd(StrUtil.DOUBLE_DOT);
+ }
+
+ /**
+ * 文件或目录是否存在
+ *
+ * - 提供路径为空则返回{@code false}
+ * - 提供路径非目录但是以'/'或'\'结尾返回{@code false}
+ * - 文件名是'.'或者'..'返回{@code false}
+ *
+ *
+ * @param path 目录
+ * @return 是否存在
+ */
+ boolean exist(final String path);
+
+ /**
+ * 判断给定路径是否为目录
+ *
+ * @param dir 被判断的路径
+ * @return 是否为目录
+ * @since 5.7.5
+ */
+ default boolean isDir(final String dir) {
+ final String workDir = pwd();
try {
- return client.printWorkingDirectory();
- } catch (final IOException e) {
- throw new IORuntimeException(e);
+ return cd(dir);
+ } finally {
+ cd(workDir);
}
}
- @Override
- public List ls(final String path) {
- return ArrayUtil.map(lsFiles(path), FTPFile::getName);
- }
-
/**
- * 遍历某个目录下所有文件和目录,不会递归遍历
- * 此方法自动过滤"."和".."两种目录
+ * 在当前远程目录(工作目录)下创建新的目录
*
- * @param path 目录
- * @param predicate 过滤器,null表示不过滤,默认去掉"."和".."两种目录
- * @return 文件名或目录名列表
+ * @param dir 目录名
+ * @return 是否创建成功
*/
- public List ls(final String path, final Predicate predicate) {
- return CollUtil.map(lsFiles(path, predicate), FTPFile::getName);
- }
+ boolean mkdir(String dir);
/**
- * 遍历某个目录下所有文件和目录,不会递归遍历
- * 此方法自动过滤"."和".."两种目录
+ * 创建指定文件夹及其父目录,从根目录开始创建,创建完成后回到默认的工作目录
*
- * @param path 目录
- * @param predicate 过滤器,null表示不过滤,默认去掉"."和".."两种目录
- * @return 文件或目录列表
- * @since 5.3.5
+ * @param dir 文件夹路径,绝对路径
*/
- public List lsFiles(final String path, final Predicate predicate) {
- final FTPFile[] ftpFiles = lsFiles(path);
- if (ArrayUtil.isEmpty(ftpFiles)) {
- return ListUtil.empty();
- }
-
- final List result = new ArrayList<>(ftpFiles.length - 2 <= 0 ? ftpFiles.length : ftpFiles.length - 2);
- String fileName;
- for (final FTPFile ftpFile : ftpFiles) {
- fileName = ftpFile.getName();
- if (!StrUtil.equals(".", fileName) && !StrUtil.equals("..", fileName)) {
- if (null == predicate || predicate.test(ftpFile)) {
- result.add(ftpFile);
- }
- }
- }
- return result;
- }
+ void mkDirs(final String dir);
/**
* 遍历某个目录下所有文件和目录,不会递归遍历
*
- * @param path 目录,如果目录不存在,抛出异常
- * @return 文件或目录列表
- * @throws FtpException 路径不存在
- * @throws IORuntimeException IO异常
+ * @param path 需要遍历的目录
+ * @return 文件和目录列表
*/
- public FTPFile[] lsFiles(final String path) throws FtpException, IORuntimeException {
- String pwd = null;
- if (StrUtil.isNotBlank(path)) {
- pwd = pwd();
- if (!cd(path)) {
- throw new FtpException("Change dir to [{}] error, maybe path not exist!", path);
- }
- }
-
- FTPFile[] ftpFiles;
- try {
- ftpFiles = this.client.listFiles();
- } catch (final IOException e) {
- throw new IORuntimeException(e);
- } finally {
- // 回到原目录
- cd(pwd);
- }
-
- return ftpFiles;
- }
-
- @Override
- public boolean mkdir(final String dir) throws IORuntimeException {
- try {
- return this.client.makeDirectory(dir);
- } catch (final IOException e) {
- throw new IORuntimeException(e);
- }
- }
+ List ls(String path);
/**
- * 获取服务端目录状态。
+ * 删除指定目录下的指定文件
*
- * @param path 路径
- * @return 状态int,服务端不同,返回不同
- * @throws IORuntimeException IO异常
- * @since 5.4.3
- */
- public int stat(final String path) throws IORuntimeException {
- try {
- return this.client.stat(path);
- } catch (final IOException e) {
- throw new IORuntimeException(e);
- }
- }
-
- /**
- * 判断ftp服务器目录内是否还有子元素(目录或文件)
- *
- * @param path 文件路径
+ * @param path 目录路径
* @return 是否存在
- * @throws IORuntimeException IO异常
*/
- public boolean existFile(final String path) throws IORuntimeException {
- final FTPFile[] ftpFileArr;
- try {
- ftpFileArr = client.listFiles(path);
- } catch (final IOException e) {
- throw new IORuntimeException(e);
- }
- return ArrayUtil.isNotEmpty(ftpFileArr);
- }
-
- @Override
- public boolean delFile(final String path) throws IORuntimeException {
- final String pwd = pwd();
- final String fileName = FileNameUtil.getName(path);
- final String dir = StrUtil.removeSuffix(path, fileName);
- if (!cd(dir)) {
- throw new FtpException("Change dir to [{}] error, maybe dir not exist!", path);
- }
-
- boolean isSuccess;
- try {
- isSuccess = client.deleteFile(fileName);
- } catch (final IOException e) {
- throw new IORuntimeException(e);
- } finally {
- // 回到原目录
- cd(pwd);
- }
- return isSuccess;
- }
-
- @Override
- public boolean delDir(final String dirPath) throws IORuntimeException {
- final FTPFile[] dirs;
- try {
- dirs = client.listFiles(dirPath);
- } catch (final IOException e) {
- throw new IORuntimeException(e);
- }
- String name;
- String childPath;
- for (final FTPFile ftpFile : dirs) {
- name = ftpFile.getName();
- childPath = StrUtil.format("{}/{}", dirPath, name);
- if (ftpFile.isDirectory()) {
- // 上级和本级目录除外
- if (!".".equals(name) && !"..".equals(name)) {
- delDir(childPath);
- }
- } else {
- delFile(childPath);
- }
- }
-
- // 删除空目录
- try {
- return this.client.removeDirectory(dirPath);
- } catch (final IOException e) {
- throw new IORuntimeException(e);
- }
- }
+ boolean delFile(String path);
/**
- * 上传文件到指定目录,可选:
+ * 删除文件夹及其文件夹下的所有文件
*
- *
- * 1. remotePath为null或""上传到当前路径
- * 2. remotePath为相对路径则相对于当前路径的子路径
- * 3. remotePath为绝对路径则上传到此路径
- *
- *
- * @param remotePath 服务端路径,可以为{@code null} 或者相对路径或绝对路径
- * @param file 文件
- * @return 是否上传成功
+ * @param dirPath 文件夹路径
+ * @return boolean 是否删除成功
*/
- @Override
- public boolean uploadFile(final String remotePath, final File file) {
- Assert.notNull(file, "file to upload is null !");
- if (!FileUtil.isFile(file)) {
- throw new FtpException("[{}] is not a file!", file);
- }
- return uploadFile(remotePath, file.getName(), file);
- }
+ boolean delDir(String dirPath);
/**
- * 上传文件到指定目录,可选:
+ * 将本地文件上传到目标服务器,目标文件名为destPath,若destPath为目录,则目标文件名将与file文件名相同。
+ * 覆盖模式
*
- *
- * 1. remotePath为null或""上传到当前路径
- * 2. remotePath为相对路径则相对于当前路径的子路径
- * 3. remotePath为绝对路径则上传到此路径
- *
- *
- * @param file 文件
- * @param remotePath 服务端路径,可以为{@code null} 或者相对路径或绝对路径
- * @param fileName 自定义在服务端保存的文件名
- * @return 是否上传成功
- * @throws IORuntimeException IO异常
+ * @param destPath 服务端路径,可以为{@code null} 或者相对路径或绝对路径
+ * @param file 需要上传的文件
+ * @return 是否成功
*/
- public boolean uploadFile(final String remotePath, final String fileName, final File file) throws IORuntimeException {
- try (final InputStream in = FileUtil.getInputStream(file)) {
- return uploadFile(remotePath, fileName, in);
- } catch (final IOException e) {
- throw new IORuntimeException(e);
- }
- }
-
- /**
- * 上传文件到指定目录,可选:
- *
- *
- * 1. remotePath为null或""上传到当前路径
- * 2. remotePath为相对路径则相对于当前路径的子路径
- * 3. remotePath为绝对路径则上传到此路径
- *
- *
- * @param remotePath 服务端路径,可以为{@code null} 或者相对路径或绝对路径
- * @param fileName 文件名
- * @param fileStream 文件流
- * @return 是否上传成功
- * @throws IORuntimeException IO异常
- */
- public boolean uploadFile(final String remotePath, final String fileName, final InputStream fileStream) throws IORuntimeException {
- try {
- client.setFileType(FTPClient.BINARY_FILE_TYPE);
- } catch (final IOException e) {
- throw new IORuntimeException(e);
- }
-
- String pwd = null;
- if (this.backToPwd) {
- pwd = pwd();
- }
-
- if (StrUtil.isNotBlank(remotePath)) {
- mkDirs(remotePath);
- if (!cd(remotePath)) {
- throw new FtpException("Change dir to [{}] error, maybe dir not exist!", remotePath);
- }
- }
-
- try {
- return client.storeFile(fileName, fileStream);
- } catch (final IOException e) {
- throw new IORuntimeException(e);
- } finally {
- if (this.backToPwd) {
- cd(pwd);
- }
- }
- }
-
- /**
- * 递归上传文件(支持目录)
- * 上传时,如果uploadFile为目录,只复制目录下所有目录和文件到目标路径下,并不会复制目录本身
- * 上传时,自动创建父级目录
- *
- * @param remotePath 目录路径
- * @param uploadFile 上传文件或目录
- */
- public void upload(final String remotePath, final File uploadFile) {
- if (!FileUtil.isDirectory(uploadFile)) {
- this.uploadFile(remotePath, uploadFile);
- return;
- }
-
- final File[] files = uploadFile.listFiles();
- if (ArrayUtil.isEmpty(files)) {
- return;
- }
-
- final List dirs = new ArrayList<>(files.length);
- //第一次只处理文件,防止目录在前面导致先处理子目录,而引发文件所在目录不正确
- for (final File f : files) {
- if (f.isDirectory()) {
- dirs.add(f);
- } else {
- this.uploadFile(remotePath, f);
- }
- }
- //第二次只处理目录
- for (final File f : dirs) {
- final String dir = FileUtil.normalize(remotePath + "/" + f.getName());
- upload(dir, f);
- }
- }
+ boolean uploadFile(String destPath, File file);
/**
* 下载文件
*
- * @param path 文件路径,包含文件名
- * @param outFile 输出文件或目录,当为目录时,使用服务端的文件名
+ * @param path 文件路径
+ * @param outFile 输出文件或目录
*/
- @Override
- public void download(final String path, final File outFile) {
- final String fileName = FileNameUtil.getName(path);
- final String dir = StrUtil.removeSuffix(path, fileName);
- download(dir, fileName, outFile);
- }
+ void download(String path, File outFile);
/**
- * 递归下载FTP服务器上文件到本地(文件目录和服务器同步)
+ * 递归下载FTP服务器上文件到本地(文件目录和服务器同步), 服务器上有新文件会覆盖本地文件
*
* @param sourcePath ftp服务器目录
* @param destDir 本地目录
+ * @since 5.3.5
*/
- @Override
- public void recursiveDownloadFolder(final String sourcePath, final File destDir) {
- String fileName;
- String srcFile;
- File destFile;
- for (final FTPFile ftpFile : lsFiles(sourcePath, null)) {
- fileName = ftpFile.getName();
- srcFile = StrUtil.format("{}/{}", sourcePath, fileName);
- destFile = FileUtil.file(destDir, fileName);
-
- if (!ftpFile.isDirectory()) {
- // 本地不存在文件或者ftp上文件有修改则下载
- if (!FileUtil.exists(destFile)
- || (ftpFile.getTimestamp().getTimeInMillis() > destFile.lastModified())) {
- download(srcFile, destFile);
- }
- } else {
- // 服务端依旧是目录,继续递归
- FileUtil.mkdir(destFile);
- recursiveDownloadFolder(srcFile, destFile);
- }
- }
- }
-
- /**
- * 下载文件
- *
- * @param path 文件所在路径(远程目录),不包含文件名
- * @param fileName 文件名
- * @param outFile 输出文件或目录,当为目录时使用服务端文件名
- * @throws IORuntimeException IO异常
- */
- public void download(final String path, final String fileName, File outFile) throws IORuntimeException {
- if (outFile.isDirectory()) {
- outFile = new File(outFile, fileName);
- }
- if (!outFile.exists()) {
- FileUtil.touch(outFile);
- }
- try (final OutputStream out = FileUtil.getOutputStream(outFile)) {
- download(path, fileName, out);
- } catch (final IOException e) {
- throw new IORuntimeException(e);
- }
- }
-
- /**
- * 下载文件到输出流
- *
- * @param path 文件路径
- * @param fileName 文件名
- * @param out 输出位置
- */
- public void download(final String path, final String fileName, final OutputStream out) {
- download(path, fileName, out, null);
- }
-
- /**
- * 下载文件到输出流
- *
- * @param path 服务端的文件路径
- * @param fileName 服务端的文件名
- * @param out 输出流,下载的文件写出到这个流中
- * @param fileNameCharset 文件名编码,通过此编码转换文件名编码为ISO8859-1
- * @throws IORuntimeException IO异常
- * @since 5.5.7
- */
- public void download(final String path, String fileName, final OutputStream out, final Charset fileNameCharset) throws IORuntimeException {
- String pwd = null;
- if (this.backToPwd) {
- pwd = pwd();
- }
-
- if (!cd(path)) {
- throw new FtpException("Change dir to [{}] error, maybe dir not exist!", path);
- }
-
- if (null != fileNameCharset) {
- fileName = new String(fileName.getBytes(fileNameCharset), StandardCharsets.ISO_8859_1);
- }
- try {
- client.setFileType(FTPClient.BINARY_FILE_TYPE);
- client.retrieveFile(fileName, out);
- } catch (final IOException e) {
- throw new IORuntimeException(e);
- } finally {
- if (backToPwd) {
- cd(pwd);
- }
- }
- }
-
- /**
- * 获取FTPClient客户端对象
- *
- * @return {@link FTPClient}
- */
- public FTPClient getClient() {
- return this.client;
- }
-
- @Override
- public void close() throws IOException {
- if (null != this.client) {
- this.client.logout();
- if (this.client.isConnected()) {
- this.client.disconnect();
- }
- this.client = null;
- }
- }
+ void recursiveDownloadFolder(String sourcePath, File destDir);
}
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/ftp/FtpConfig.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/ftp/FtpConfig.java
index 036fe5cb2..8ddaaee15 100644
--- a/hutool-extra/src/main/java/org/dromara/hutool/extra/ftp/FtpConfig.java
+++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/ftp/FtpConfig.java
@@ -12,6 +12,8 @@
package org.dromara.hutool.extra.ftp;
+import org.dromara.hutool.extra.ssh.Connector;
+
import java.io.Serializable;
import java.nio.charset.Charset;
@@ -32,44 +34,24 @@ public class FtpConfig implements Serializable {
return new FtpConfig();
}
- /**
- * 主机
- */
- private String host;
- /**
- * 端口
- */
- private int port;
- /**
- * 用户名
- */
- private String user;
- /**
- * 密码
- */
- private String password;
+ private Connector connector;
/**
* 编码
*/
private Charset charset;
- /**
- * 连接超时时长,单位毫秒
- */
- private long connectionTimeout;
-
/**
* Socket连接超时时长,单位毫秒
*/
private long soTimeout;
/**
- * 设置服务器语言
+ * 服务器语言
*/
private String serverLanguageCode;
/**
- * 设置服务器系统关键词
+ * 服务器系统关键词
*/
private String systemKey;
@@ -82,114 +64,137 @@ public class FtpConfig implements Serializable {
/**
* 构造
*
- * @param host 主机
- * @param port 端口
- * @param user 用户名
- * @param password 密码
- * @param charset 编码
+ * @param connector 连接信息,包括host、port、user、password等信息
+ * @param charset 编码
*/
- public FtpConfig(final String host, final int port, final String user, final String password, final Charset charset) {
- this(host, port, user, password, charset, null, null);
+ public FtpConfig(final Connector connector, final Charset charset) {
+ this(connector, charset, null, null);
}
/**
* 构造
*
- * @param host 主机
- * @param port 端口
- * @param user 用户名
- * @param password 密码
+ * @param connector 连接信息,包括host、port、user、password等信息
* @param charset 编码
* @param serverLanguageCode 服务器语言
* @param systemKey 系统关键字
- * @since 5.5.7
*/
- public FtpConfig(final String host, final int port, final String user, final String password, final Charset charset, final String serverLanguageCode, final String systemKey) {
- this.host = host;
- this.port = port;
- this.user = user;
- this.password = password;
+ public FtpConfig(final Connector connector, final Charset charset, final String serverLanguageCode, final String systemKey) {
+ this.connector = connector;
this.charset = charset;
this.serverLanguageCode = serverLanguageCode;
this.systemKey = systemKey;
}
- public String getHost() {
- return host;
+ /**
+ * 获取连接信息
+ *
+ * @return 连接信息
+ */
+ public Connector getConnector() {
+ return connector;
}
- public FtpConfig setHost(final String host) {
- this.host = host;
+ /**
+ * 设置连接信息
+ *
+ * @param connector 连接信息
+ * @return this
+ */
+ public FtpConfig setConnector(final Connector connector) {
+ this.connector = connector;
return this;
}
- public int getPort() {
- return port;
- }
-
- public FtpConfig setPort(final int port) {
- this.port = port;
- return this;
- }
-
- public String getUser() {
- return user;
- }
-
- public FtpConfig setUser(final String user) {
- this.user = user;
- return this;
- }
-
- public String getPassword() {
- return password;
- }
-
- public FtpConfig setPassword(final String password) {
- this.password = password;
+ /**
+ * 设置超时,注意此方法会调用{@link Connector#setTimeout(long)}
+ * 此方法需在{@link #setConnector(Connector)}后调用,否则会创建空的Connector
+ * @param timeout 链接超时
+ * @return this
+ */
+ public FtpConfig setConnectionTimeout(final long timeout){
+ if(null == connector){
+ connector = Connector.of();
+ }
+ connector.setTimeout(timeout);
return this;
}
+ /**
+ * 获取编码
+ *
+ * @return 编码
+ */
public Charset getCharset() {
return charset;
}
+ /**
+ * 设置编码
+ *
+ * @param charset 编码
+ * @return this
+ */
public FtpConfig setCharset(final Charset charset) {
this.charset = charset;
return this;
}
- public long getConnectionTimeout() {
- return connectionTimeout;
- }
-
- public FtpConfig setConnectionTimeout(final long connectionTimeout) {
- this.connectionTimeout = connectionTimeout;
- return this;
- }
-
+ /**
+ * 获取读取数据超时时间
+ *
+ * @return 读取数据超时时间
+ */
public long getSoTimeout() {
return soTimeout;
}
+ /**
+ * 设置读取数据超时时间
+ *
+ * @param soTimeout 读取数据超时时间
+ * @return this
+ */
public FtpConfig setSoTimeout(final long soTimeout) {
this.soTimeout = soTimeout;
return this;
}
+ /**
+ * 获取服务器语言
+ *
+ * @return 服务器语言
+ */
public String getServerLanguageCode() {
return serverLanguageCode;
}
+ /**
+ * 设置服务器语言
+ *
+ * @param serverLanguageCode 服务器语言
+ * @return this
+ */
public FtpConfig setServerLanguageCode(final String serverLanguageCode) {
this.serverLanguageCode = serverLanguageCode;
return this;
}
+ /**
+ * 获取服务器系统关键词
+ *
+ * @return 服务器系统关键词
+ */
public String getSystemKey() {
return systemKey;
}
+ /**
+ * 设置服务器系统关键词
+ *
+ * @param systemKey 服务器系统关键词
+ * @return this
+ */
public FtpConfig setSystemKey(final String systemKey) {
this.systemKey = systemKey;
return this;
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/ftp/FtpMode.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/ftp/FtpMode.java
index 7c76b4577..1ecc89fe7 100644
--- a/hutool-extra/src/main/java/org/dromara/hutool/extra/ftp/FtpMode.java
+++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/ftp/FtpMode.java
@@ -22,8 +22,13 @@ package org.dromara.hutool.extra.ftp;
* @since 4.1.19
*/
public enum FtpMode {
- /** 主动模式 */
+
+ /**
+ * 主动模式
+ */
Active,
- /** 被动模式 */
+ /**
+ * 被动模式
+ */
Passive
}
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/Connector.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/Connector.java
index fddfcd22f..44e257fd7 100644
--- a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/Connector.java
+++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/Connector.java
@@ -13,16 +13,59 @@
package org.dromara.hutool.extra.ssh;
/**
- * 连接者对象,提供一些连接的基本信息
+ * 连接者对象,提供一些连接的基本信息,包括:
+ *
+ * - host:主机名
+ * - port:端口
+ * - user:用户名(默认root)
+ * - password:密码
+ * - timeout:连接超时毫秒数
+ *
*
* @author looly
*/
public class Connector {
+
+ /**
+ * 创建Connector,所有参数为默认,用于构建模式
+ *
+ * @return Connector
+ */
+ public static Connector of() {
+ return new Connector();
+ }
+
+ /**
+ * 创建Connector
+ *
+ * @param host 主机名
+ * @param port 端口
+ * @param user 用户名
+ * @param password 密码
+ * @return Connector
+ */
+ public static Connector of(final String host, final int port, final String user, final String password) {
+ return of(host, port, user, password, 0);
+ }
+
+ /**
+ * 创建Connector
+ *
+ * @param host 主机名
+ * @param port 端口
+ * @param user 用户名
+ * @param password 密码
+ * @param timeout 连接超时时长,0表示默认
+ * @return Connector
+ */
+ public static Connector of(final String host, final int port, final String user, final String password, final long timeout) {
+ return new Connector(host, port, user, password, timeout);
+ }
+
private String host;
private int port;
private String user = "root";
private String password;
- private String group;
private long timeout;
/**
@@ -31,19 +74,6 @@ public class Connector {
public Connector() {
}
- /**
- * 构造
- *
- * @param user 用户名
- * @param password 密码
- * @param group 组
- */
- public Connector(final String user, final String password, final String group) {
- this.user = user;
- this.password = password;
- this.group = group;
- }
-
/**
* 构造
*
@@ -51,19 +81,7 @@ public class Connector {
* @param port 端口
* @param user 用户名
* @param password 密码
- */
- public Connector(final String host, final int port, final String user, final String password) {
- this(host, port, user, password, 0);
- }
-
- /**
- * 构造
- *
- * @param host 主机名
- * @param port 端口
- * @param user 用户名
- * @param password 密码
- * @param timeout 连接超时时长,0表示默认
+ * @param timeout 连接超时时长,0表示默认
*/
public Connector(final String host, final int port, final String user, final String password, final long timeout) {
this.host = host;
@@ -86,9 +104,11 @@ public class Connector {
* 设定主机名
*
* @param host 主机名
+ * @return this
*/
- public void setHost(final String host) {
+ public Connector setHost(final String host) {
this.host = host;
+ return this;
}
/**
@@ -104,9 +124,11 @@ public class Connector {
* 设定端口号
*
* @param port 端口号
+ * @return this
*/
- public void setPort(final int port) {
+ public Connector setPort(final int port) {
this.port = port;
+ return this;
}
/**
@@ -122,9 +144,11 @@ public class Connector {
* 设定用户名
*
* @param name 用户名
+ * @return this
*/
- public void setUser(final String name) {
+ public Connector setUser(final String name) {
this.user = name;
+ return this;
}
/**
@@ -140,27 +164,11 @@ public class Connector {
* 设定密码
*
* @param password 密码
+ * @return this
*/
- public void setPassword(final String password) {
+ public Connector setPassword(final String password) {
this.password = password;
- }
-
- /**
- * 获得用户组名
- *
- * @return 用户组
- */
- public String getGroup() {
- return group;
- }
-
- /**
- * 设定用户组名
- *
- * @param group 用户组
- */
- public void setGroup(final String group) {
- this.group = group;
+ return this;
}
/**
@@ -176,9 +184,11 @@ public class Connector {
* 设置连接超时时间
*
* @param timeout 连接超时时间
+ * @return this
*/
- public void setTimeout(final long timeout) {
+ public Connector setTimeout(final long timeout) {
this.timeout = timeout;
+ return this;
}
/**
@@ -191,7 +201,6 @@ public class Connector {
", port=" + port +
", user='" + user + '\'' +
", password='" + password + '\'' +
- ", group='" + group + '\'' +
", timeout=" + timeout +
'}';
}
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/JschSftp.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/JschSftp.java
index 1ffd3e869..8af81ab47 100644
--- a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/JschSftp.java
+++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/JschSftp.java
@@ -52,8 +52,7 @@ public class JschSftp extends AbstractFtp {
private Session session;
private ChannelSftp channel;
- // ---------------------------------------------------------------------------------------- Constructor start
-
+ //region ----- of
/**
* 构造
*
@@ -61,9 +60,10 @@ public class JschSftp extends AbstractFtp {
* @param sshPort 远程主机端口
* @param sshUser 远程主机用户名
* @param sshPass 远程主机密码
+ * @return JschSftp
*/
- public JschSftp(final String sshHost, final int sshPort, final String sshUser, final String sshPass) {
- this(sshHost, sshPort, sshUser, sshPass, DEFAULT_CHARSET);
+ public static JschSftp of(final String sshHost, final int sshPort, final String sshUser, final String sshPass) {
+ return of(sshHost, sshPort, sshUser, sshPass, DEFAULT_CHARSET);
}
/**
@@ -74,11 +74,12 @@ public class JschSftp extends AbstractFtp {
* @param sshUser 远程主机用户名
* @param sshPass 远程主机密码
* @param charset 编码
- * @since 4.1.14
+ * @return JschSftp
*/
- public JschSftp(final String sshHost, final int sshPort, final String sshUser, final String sshPass, final Charset charset) {
- this(new FtpConfig(sshHost, sshPort, sshUser, sshPass, charset));
+ public static JschSftp of(final String sshHost, final int sshPort, final String sshUser, final String sshPass, final Charset charset) {
+ return new JschSftp(new FtpConfig(Connector.of(sshHost, sshPort, sshUser, sshPass), charset));
}
+ // endregion
/**
* 构造
@@ -132,20 +133,22 @@ public class JschSftp extends AbstractFtp {
init();
}
// ---------------------------------------------------------------------------------------- Constructor end
+
/**
* 初始化
*/
@SuppressWarnings("resource")
public void init() {
- if(null == this.channel){
- if(null == this.session){
+ if (null == this.channel) {
+ if (null == this.session) {
final FtpConfig config = this.ftpConfig;
- this.session = new JschSession(new Connector(
- config.getHost(),
- config.getPort(),
- config.getUser(),
- config.getPassword(),
- config.getConnectionTimeout()))
+ final Connector connector = config.getConnector();
+ this.session = new JschSession(Connector.of(
+ connector.getHost(),
+ connector.getPort(),
+ connector.getUser(),
+ connector.getPassword(),
+ connector.getTimeout()))
.getRaw();
}
@@ -158,8 +161,8 @@ public class JschSftp extends AbstractFtp {
}
try {
- if(!channel.isConnected()){
- channel.connect((int) Math.max(this.ftpConfig.getConnectionTimeout(), 0));
+ if (!channel.isConnected()) {
+ channel.connect((int) Math.max(this.ftpConfig.getConnector().getTimeout(), 0));
}
channel.setFilenameEncoding(this.ftpConfig.getCharset().toString());
} catch (final JSchException | SftpException e) {
@@ -169,7 +172,7 @@ public class JschSftp extends AbstractFtp {
@Override
public JschSftp reconnectIfTimeout() {
- if (StrUtil.isBlank(this.ftpConfig.getHost())) {
+ if (StrUtil.isBlank(this.ftpConfig.getConnector().getHost())) {
throw new FtpException("Host is blank!");
}
try {
@@ -188,7 +191,7 @@ public class JschSftp extends AbstractFtp {
* @since 4.1.14
*/
public ChannelSftp getClient() {
- if(false == this.channel.isConnected()){
+ if (false == this.channel.isConnected()) {
init();
}
return this.channel;
@@ -462,7 +465,7 @@ public class JschSftp extends AbstractFtp {
@SuppressWarnings("resource")
@Override
public boolean uploadFile(final String destPath, final File file) {
- if(!FileUtil.isFile(file)){
+ if (!FileUtil.isFile(file)) {
throw new FtpException("[{}] is not a file!", file);
}
this.mkDirs(destPath);
@@ -585,7 +588,7 @@ public class JschSftp extends AbstractFtp {
if (!item.getAttrs().isDir()) {
// 本地不存在文件或者ftp上文件有修改则下载
if (!FileUtil.exists(destFile)
- || (item.getAttrs().getMTime() > (destFile.lastModified() / 1000))) {
+ || (item.getAttrs().getMTime() > (destFile.lastModified() / 1000))) {
download(srcFile, destFile);
}
} else {
@@ -638,11 +641,12 @@ public class JschSftp extends AbstractFtp {
@Override
public String toString() {
- return "Sftp{" +
- "host='" + this.ftpConfig.getHost() + '\'' +
- ", port=" + this.ftpConfig.getPort() +
- ", user='" + this.ftpConfig.getUser() + '\'' +
- '}';
+ final Connector connector = this.ftpConfig.getConnector();
+ return "JschSftp{" +
+ "host='" + connector.getHost() + '\'' +
+ ", port=" + connector.getPort() +
+ ", user='" + connector.getUser() + '\'' +
+ '}';
}
/**
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/sshj/SshjSftp.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/sshj/SshjSftp.java
index e37d4e0fe..e08723422 100644
--- a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/sshj/SshjSftp.java
+++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/sshj/SshjSftp.java
@@ -20,7 +20,6 @@ import net.schmizz.sshj.xfer.FileSystemFile;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.core.text.StrUtil;
-import org.dromara.hutool.core.util.CharsetUtil;
import org.dromara.hutool.extra.ftp.AbstractFtp;
import org.dromara.hutool.extra.ftp.FtpConfig;
import org.dromara.hutool.extra.ftp.FtpException;
@@ -45,27 +44,17 @@ import java.util.List;
*/
public class SshjSftp extends AbstractFtp {
- private SSHClient ssh;
- private SFTPClient sftp;
-
- /**
- * 构造,使用默认端口
- *
- * @param sshHost 主机
- */
- public SshjSftp(final String sshHost) {
- this(new FtpConfig(sshHost, 22, null, null, CharsetUtil.UTF_8));
- }
-
+ // region ----- of
/**
* 构造
*
* @param sshHost 主机
* @param sshUser 用户名
* @param sshPass 密码
+ * @return SshjSftp
*/
- public SshjSftp(final String sshHost, final String sshUser, final String sshPass) {
- this(new FtpConfig(sshHost, 22, sshUser, sshPass, CharsetUtil.UTF_8));
+ public static SshjSftp of(final String sshHost, final String sshUser, final String sshPass) {
+ return of(sshHost, 22, sshUser, sshPass);
}
/**
@@ -75,9 +64,10 @@ public class SshjSftp extends AbstractFtp {
* @param sshPort 端口
* @param sshUser 用户名
* @param sshPass 密码
+ * @return SshjSftp
*/
- public SshjSftp(final String sshHost, final int sshPort, final String sshUser, final String sshPass) {
- this(new FtpConfig(sshHost, sshPort, sshUser, sshPass, CharsetUtil.UTF_8));
+ public static SshjSftp of(final String sshHost, final int sshPort, final String sshUser, final String sshPass) {
+ return of(sshHost, sshPort, sshUser, sshPass, DEFAULT_CHARSET);
}
/**
@@ -88,10 +78,15 @@ public class SshjSftp extends AbstractFtp {
* @param sshUser 用户名
* @param sshPass 密码
* @param charset 编码
+ * @return SshjSftp
*/
- public SshjSftp(final String sshHost, final int sshPort, final String sshUser, final String sshPass, final Charset charset) {
- this(new FtpConfig(sshHost, sshPort, sshUser, sshPass, charset));
+ public static SshjSftp of(final String sshHost, final int sshPort, final String sshUser, final String sshPass, final Charset charset) {
+ return new SshjSftp(new FtpConfig(Connector.of(sshHost, sshPort, sshUser, sshPass), charset));
}
+ //endregion
+
+ private SSHClient ssh;
+ private SFTPClient sftp;
/**
* 构造
@@ -106,8 +101,9 @@ public class SshjSftp extends AbstractFtp {
/**
* 构造
+ *
* @param sshClient {@link SSHClient}
- * @param charset 编码
+ * @param charset 编码
*/
public SshjSftp(final SSHClient sshClient, final Charset charset) {
super(FtpConfig.of().setCharset(charset));
@@ -122,12 +118,7 @@ public class SshjSftp extends AbstractFtp {
* @since 5.7.18
*/
public void init() {
- this.ssh = SshjUtil.openClient(new Connector(
- ftpConfig.getHost(),
- ftpConfig.getPort(),
- ftpConfig.getUser(),
- ftpConfig.getPassword(),
- ftpConfig.getConnectionTimeout()));
+ this.ssh = SshjUtil.openClient(this.ftpConfig.getConnector());
try {
ssh.setRemoteCharset(ftpConfig.getCharset());
@@ -139,7 +130,7 @@ public class SshjSftp extends AbstractFtp {
@Override
public AbstractFtp reconnectIfTimeout() {
- if (StrUtil.isBlank(this.ftpConfig.getHost())) {
+ if (StrUtil.isBlank(this.ftpConfig.getConnector().getHost())) {
throw new FtpException("Host is blank!");
}
try {
diff --git a/hutool-extra/src/test/java/org/dromara/hutool/extra/ftp/FtpTest.java b/hutool-extra/src/test/java/org/dromara/hutool/extra/ftp/FtpTest.java
index 027e7d885..c08a5a06b 100644
--- a/hutool-extra/src/test/java/org/dromara/hutool/extra/ftp/FtpTest.java
+++ b/hutool-extra/src/test/java/org/dromara/hutool/extra/ftp/FtpTest.java
@@ -28,7 +28,7 @@ public class FtpTest {
@Disabled
public void ftpsTest() {
final FTPSClient ftpsClient = new FTPSClient();
- final Ftp ftp = new Ftp(ftpsClient);
+ final CommonsFtp ftp = new CommonsFtp(ftpsClient);
ftp.cd("/file/aaa");
Console.log(ftp.pwd());
@@ -39,7 +39,7 @@ public class FtpTest {
@Test
@Disabled
public void cdTest() {
- final Ftp ftp = new Ftp("looly.centos");
+ final CommonsFtp ftp = CommonsFtp.of("looly.centos");
ftp.cd("/file/aaa");
Console.log(ftp.pwd());
@@ -50,7 +50,7 @@ public class FtpTest {
@Test
@Disabled
public void uploadTest() {
- final Ftp ftp = new Ftp("localhost");
+ final CommonsFtp ftp = CommonsFtp.of("localhost");
final boolean upload = ftp.uploadFile("/temp", FileUtil.file("d:/test/test.zip"));
Console.log(upload);
@@ -61,17 +61,17 @@ public class FtpTest {
@Test
@Disabled
public void reconnectIfTimeoutTest() throws InterruptedException {
- final Ftp ftp = new Ftp("looly.centos");
+ final CommonsFtp ftp = CommonsFtp.of("looly.centos");
Console.log("打印pwd: " + ftp.pwd());
Console.log("休眠一段时间,然后再次发送pwd命令,抛出异常表明连接超时");
Thread.sleep(35 * 1000);
- try{
+ try {
Console.log("打印pwd: " + ftp.pwd());
- }catch (final FtpException e) {
- e.printStackTrace();
+ } catch (final FtpException e) {
+ Console.error(e, e.getMessage());
}
Console.log("判断是否超时并重连...");
@@ -85,8 +85,8 @@ public class FtpTest {
@Test
@Disabled
public void recursiveDownloadFolder() {
- final Ftp ftp = new Ftp("looly.centos");
- ftp.recursiveDownloadFolder("/",FileUtil.file("d:/test/download"));
+ final CommonsFtp ftp = CommonsFtp.of("looly.centos");
+ ftp.recursiveDownloadFolder("/", FileUtil.file("d:/test/download"));
IoUtil.closeQuietly(ftp);
}
@@ -94,11 +94,11 @@ public class FtpTest {
@Test
@Disabled
public void recursiveDownloadFolderSftp() {
- final JschSftp ftp = new JschSftp("127.0.0.1", 22, "test", "test");
+ final JschSftp ftp = JschSftp.of("127.0.0.1", 22, "test", "test");
ftp.cd("/file/aaa");
Console.log(ftp.pwd());
- ftp.recursiveDownloadFolder("/",FileUtil.file("d:/test/download"));
+ ftp.recursiveDownloadFolder("/", FileUtil.file("d:/test/download"));
IoUtil.closeQuietly(ftp);
}
@@ -106,13 +106,13 @@ public class FtpTest {
@Test
@Disabled
public void downloadTest() {
- final Ftp ftp = new Ftp("localhost");
+ final CommonsFtp ftp = CommonsFtp.of("localhost");
final List fileNames = ftp.ls("temp/");
- for(final String name: fileNames) {
+ for (final String name : fileNames) {
ftp.download("",
- name,
- FileUtil.file("d:/test/download/" + name));
+ name,
+ FileUtil.file("d:/test/download/" + name));
}
IoUtil.closeQuietly(ftp);
@@ -121,7 +121,7 @@ public class FtpTest {
@Test
@Disabled
public void isDirTest() throws Exception {
- try (final Ftp ftp = new Ftp("127.0.0.1", 21)) {
+ try (final CommonsFtp ftp = CommonsFtp.of("127.0.0.1", 21)) {
Console.log(ftp.pwd());
ftp.isDir("/test");
Console.log(ftp.pwd());
@@ -131,7 +131,7 @@ public class FtpTest {
@Test
@Disabled
public void existSftpTest() {
- try (final JschSftp ftp = new JschSftp("127.0.0.1", 22, "test", "test")) {
+ try (final JschSftp ftp = JschSftp.of("127.0.0.1", 22, "test", "test")) {
Console.log(ftp.pwd());
Console.log(ftp.exist(null));
Console.log(ftp.exist(""));
@@ -154,7 +154,7 @@ public class FtpTest {
@Test
@Disabled
public void existFtpTest() throws Exception {
- try (final Ftp ftp = new Ftp("127.0.0.1", 21)) {
+ try (final CommonsFtp ftp = CommonsFtp.of("127.0.0.1", 21)) {
Console.log(ftp.pwd());
Console.log(ftp.exist(null));
Console.log(ftp.exist(""));
diff --git a/hutool-extra/src/test/java/org/dromara/hutool/extra/ssh/JschTest.java b/hutool-extra/src/test/java/org/dromara/hutool/extra/ssh/JschTest.java
index 27bec7d4e..afb397b8b 100644
--- a/hutool-extra/src/test/java/org/dromara/hutool/extra/ssh/JschTest.java
+++ b/hutool-extra/src/test/java/org/dromara/hutool/extra/ssh/JschTest.java
@@ -35,7 +35,7 @@ public class JschTest {
@Disabled
public void bindPortTest() {
//新建会话,此会话用于ssh连接到跳板机(堡垒机),此处为10.1.1.1:22
- final JschSession session = new JschSession(new Connector("looly.centos", 22, "test", "123456"));
+ final JschSession session = new JschSession(Connector.of("looly.centos", 22, "test", "123456"));
// 将堡垒机保护的内网8080端口映射到localhost,我们就可以通过访问http://localhost:8080/访问内网服务了
session.bindLocalPort(8080, new InetSocketAddress("172.20.12.123", 8080));
}
@@ -45,7 +45,7 @@ public class JschTest {
@Disabled
public void bindRemotePort() {
// 建立会话
- final JschSession session = new JschSession(new Connector("looly.centos", 22, "test", "123456"));
+ final JschSession session = new JschSession(Connector.of("looly.centos", 22, "test", "123456"));
// 绑定ssh服务端8089端口到本机的8000端口上
session.bindRemotePort(new InetSocketAddress(8089), new InetSocketAddress("localhost", 8000));
// 保证一直运行
@@ -55,7 +55,7 @@ public class JschTest {
@Test
@Disabled
public void sftpTest() {
- final JschSession session = new JschSession(new Connector("looly.centos", 22, "root", "123456"));
+ final JschSession session = new JschSession(Connector.of("looly.centos", 22, "root", "123456"));
final JschSftp jschSftp = session.openSftp(CharsetUtil.UTF_8);
jschSftp.mkDirs("/opt/test/aaa/bbb");
Console.log("OK");
@@ -65,7 +65,7 @@ public class JschTest {
@Test
@Disabled
public void reconnectIfTimeoutTest() throws InterruptedException {
- final JschSession session = new JschSession(new Connector("sunnyserver", 22,"mysftp","liuyang1234"));
+ final JschSession session = new JschSession(Connector.of("sunnyserver", 22,"mysftp","liuyang1234"));
final JschSftp jschSftp = session.openSftp(CharsetUtil.UTF_8);
Console.log("打印pwd: " + jschSftp.pwd());
diff --git a/hutool-extra/src/test/java/org/dromara/hutool/extra/ssh/SftpTest.java b/hutool-extra/src/test/java/org/dromara/hutool/extra/ssh/SftpTest.java
index 7e887c1d1..ec115f2a5 100644
--- a/hutool-extra/src/test/java/org/dromara/hutool/extra/ssh/SftpTest.java
+++ b/hutool-extra/src/test/java/org/dromara/hutool/extra/ssh/SftpTest.java
@@ -34,7 +34,7 @@ public class SftpTest {
@BeforeEach
@Disabled
public void init() {
- sshjSftp = new SshjSftp("ip", 22, "test", "test", CharsetUtil.UTF_8);
+ sshjSftp = SshjSftp.of("ip", 22, "test", "test");
}
@Test