mirror of
https://gitee.com/dromara/hutool.git
synced 2025-05-03 20:27:58 +08:00
fix code and add Ftp
This commit is contained in:
parent
3eec56008c
commit
004d4f407d
@ -13,15 +13,12 @@
|
||||
package org.dromara.hutool.extra.ftp;
|
||||
|
||||
import org.dromara.hutool.core.collection.CollUtil;
|
||||
import org.dromara.hutool.core.io.file.FileUtil;
|
||||
import org.dromara.hutool.core.io.file.FileNameUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.io.file.FileUtil;
|
||||
import org.dromara.hutool.core.text.CharUtil;
|
||||
import org.dromara.hutool.core.util.CharsetUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -30,15 +27,15 @@ import java.util.List;
|
||||
* @author looly
|
||||
* @since 4.1.14
|
||||
*/
|
||||
public abstract class AbstractFtp implements Closeable {
|
||||
|
||||
/**
|
||||
* 默认编码
|
||||
*/
|
||||
public static final Charset DEFAULT_CHARSET = CharsetUtil.UTF_8;
|
||||
public abstract class AbstractFtp implements Ftp {
|
||||
|
||||
protected FtpConfig ftpConfig;
|
||||
|
||||
@Override
|
||||
public FtpConfig getConfig() {
|
||||
return this.ftpConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
@ -49,74 +46,7 @@ public abstract class AbstractFtp implements Closeable {
|
||||
this.ftpConfig = config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果连接超时的话,重新进行连接
|
||||
*
|
||||
* @return this
|
||||
* @since 4.5.2
|
||||
*/
|
||||
public abstract AbstractFtp reconnectIfTimeout();
|
||||
|
||||
/**
|
||||
* 打开指定目录,具体逻辑取决于实现,例如在FTP中,进入失败返回{@code false}, SFTP中则抛出异常
|
||||
*
|
||||
* @param directory directory
|
||||
* @return 是否打开目录
|
||||
*/
|
||||
public abstract boolean cd(String directory);
|
||||
|
||||
/**
|
||||
* 打开上级目录
|
||||
*
|
||||
* @return 是否打开目录
|
||||
* @since 4.0.5
|
||||
*/
|
||||
public boolean toParent() {
|
||||
return cd("..");
|
||||
}
|
||||
|
||||
/**
|
||||
* 远程当前目录(工作目录)
|
||||
*
|
||||
* @return 远程当前目录
|
||||
*/
|
||||
public abstract String pwd();
|
||||
|
||||
/**
|
||||
* 判断给定路径是否为目录
|
||||
*
|
||||
* @param dir 被判断的路径
|
||||
* @return 是否为目录
|
||||
* @since 5.7.5
|
||||
*/
|
||||
public boolean isDir(final String dir) {
|
||||
final String workDir = pwd();
|
||||
try {
|
||||
return cd(dir);
|
||||
} finally {
|
||||
cd(workDir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在当前远程目录(工作目录)下创建新的目录
|
||||
*
|
||||
* @param dir 目录名
|
||||
* @return 是否创建成功
|
||||
*/
|
||||
public abstract boolean mkdir(String dir);
|
||||
|
||||
/**
|
||||
* 文件或目录是否存在<br>
|
||||
* <ul>
|
||||
* <li>提供路径为空则返回{@code false}</li>
|
||||
* <li>提供路径非目录但是以'/'或'\'结尾返回{@code false}</li>
|
||||
* <li>文件名是'.'或者'..'返回{@code false}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param path 目录
|
||||
* @return 是否存在
|
||||
*/
|
||||
@Override
|
||||
public boolean exist(final String path) {
|
||||
if (StrUtil.isBlank(path)) {
|
||||
return false;
|
||||
@ -130,12 +60,12 @@ public abstract class AbstractFtp implements Closeable {
|
||||
}
|
||||
|
||||
final String fileName = FileNameUtil.getName(path);
|
||||
if (".".equals(fileName) || "..".equals(fileName)) {
|
||||
if (StrUtil.DOT.equals(fileName) || StrUtil.DOUBLE_DOT.equals(fileName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 文件验证
|
||||
final String dir = StrUtil.defaultIfEmpty(StrUtil.removeSuffix(path, fileName), ".");
|
||||
final String dir = StrUtil.defaultIfEmpty(StrUtil.removeSuffix(path, fileName), StrUtil.DOT);
|
||||
// issue#I7CSQ9 检查父目录为目录且是否存在
|
||||
if (!isDir(dir)) {
|
||||
return false;
|
||||
@ -149,35 +79,7 @@ public abstract class AbstractFtp implements Closeable {
|
||||
return containsIgnoreCase(names, fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 遍历某个目录下所有文件和目录,不会递归遍历
|
||||
*
|
||||
* @param path 需要遍历的目录
|
||||
* @return 文件和目录列表
|
||||
*/
|
||||
public abstract List<String> ls(String path);
|
||||
|
||||
/**
|
||||
* 删除指定目录下的指定文件
|
||||
*
|
||||
* @param path 目录路径
|
||||
* @return 是否存在
|
||||
*/
|
||||
public abstract boolean delFile(String path);
|
||||
|
||||
/**
|
||||
* 删除文件夹及其文件夹下的所有文件
|
||||
*
|
||||
* @param dirPath 文件夹路径
|
||||
* @return boolean 是否删除成功
|
||||
*/
|
||||
public abstract boolean delDir(String dirPath);
|
||||
|
||||
/**
|
||||
* 创建指定文件夹及其父目录,从根目录开始创建,创建完成后回到默认的工作目录
|
||||
*
|
||||
* @param dir 文件夹路径,绝对路径
|
||||
*/
|
||||
@Override
|
||||
public void mkDirs(final String dir) {
|
||||
final String[] dirs = StrUtil.trim(dir).split("[\\\\/]+");
|
||||
|
||||
@ -207,24 +109,6 @@ public abstract class AbstractFtp implements Closeable {
|
||||
cd(now);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将本地文件上传到目标服务器,目标文件名为destPath,若destPath为目录,则目标文件名将与file文件名相同。
|
||||
* 覆盖模式
|
||||
*
|
||||
* @param destPath 服务端路径,可以为{@code null} 或者相对路径或绝对路径
|
||||
* @param file 需要上传的文件
|
||||
* @return 是否成功
|
||||
*/
|
||||
public abstract boolean uploadFile(String destPath, File file);
|
||||
|
||||
/**
|
||||
* 下载文件
|
||||
*
|
||||
* @param path 文件路径
|
||||
* @param outFile 输出文件或目录
|
||||
*/
|
||||
public abstract void download(String path, File outFile);
|
||||
|
||||
/**
|
||||
* 下载文件-避免未完成的文件<br>
|
||||
* 来自:<a href="https://gitee.com/dromara/hutool/pulls/407">https://gitee.com/dromara/hutool/pulls/407</a><br>
|
||||
@ -260,15 +144,6 @@ public abstract class AbstractFtp implements Closeable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归下载FTP服务器上文件到本地(文件目录和服务器同步), 服务器上有新文件会覆盖本地文件
|
||||
*
|
||||
* @param sourcePath ftp服务器目录
|
||||
* @param destDir 本地目录
|
||||
* @since 5.3.5
|
||||
*/
|
||||
public abstract void recursiveDownloadFolder(String sourcePath, File destDir);
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------------------------- Private method start
|
||||
|
||||
/**
|
||||
@ -279,18 +154,10 @@ public abstract class AbstractFtp implements Closeable {
|
||||
* @return 是否包含
|
||||
*/
|
||||
private static boolean containsIgnoreCase(final List<String> names, final String nameToFind) {
|
||||
if (CollUtil.isEmpty(names)) {
|
||||
return false;
|
||||
}
|
||||
if (StrUtil.isEmpty(nameToFind)) {
|
||||
return false;
|
||||
}
|
||||
for (final String name : names) {
|
||||
if (nameToFind.equalsIgnoreCase(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return CollUtil.contains(names, nameToFind::equalsIgnoreCase);
|
||||
}
|
||||
// ---------------------------------------------------------------------------------------------------------------------------------------- Private method end
|
||||
}
|
||||
|
@ -0,0 +1,750 @@
|
||||
/*
|
||||
* 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.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.dromara.hutool.core.array.ArrayUtil;
|
||||
import org.dromara.hutool.core.collection.CollUtil;
|
||||
import org.dromara.hutool.core.collection.ListUtil;
|
||||
import org.dromara.hutool.core.io.IORuntimeException;
|
||||
import org.dromara.hutool.core.io.file.FileNameUtil;
|
||||
import org.dromara.hutool.core.io.file.FileUtil;
|
||||
import org.dromara.hutool.core.lang.Assert;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.extra.ssh.Connector;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Apache Commons FTP客户端封装<br>
|
||||
* 此客户端基于Apache-Commons-Net
|
||||
* <p>
|
||||
* 常见搭建ftp的工具有:
|
||||
* <ul>
|
||||
* <li>filezila server ;根目录一般都是空</li>
|
||||
* <li>linux vsftpd ; 使用的 系统用户的目录,这里往往都是不是根目录,如:/home/hutool/ftp</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Looly
|
||||
*/
|
||||
public class CommonsFtp extends AbstractFtp {
|
||||
|
||||
/**
|
||||
* 默认端口
|
||||
*/
|
||||
public static final int DEFAULT_PORT = 21;
|
||||
|
||||
// region ----- of
|
||||
/**
|
||||
* 构造CommonsFtp,匿名登录
|
||||
*
|
||||
* @param host 域名或IP
|
||||
* @return CommonsFtp
|
||||
*/
|
||||
public static CommonsFtp of(final String host) {
|
||||
return of(host, DEFAULT_PORT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造,匿名登录
|
||||
*
|
||||
* @param host 域名或IP
|
||||
* @param port 端口
|
||||
* @return CommonsFtp
|
||||
*/
|
||||
public static CommonsFtp of(final String host, final int port) {
|
||||
return of(host, port, "anonymous", StrUtil.EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param host 域名或IP
|
||||
* @param port 端口
|
||||
* @param user 用户名
|
||||
* @param password 密码
|
||||
* @return CommonsFtp
|
||||
*/
|
||||
public static CommonsFtp of(final String host, final int port, final String user, final String password) {
|
||||
return of(Connector.of(host, port, user, password), DEFAULT_CHARSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param connector 连接信息,包括host、port、user、password等信息
|
||||
* @param charset 编码
|
||||
* @return CommonsFtp
|
||||
*/
|
||||
public static CommonsFtp of(final Connector connector, final Charset charset) {
|
||||
return of(connector, charset, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param connector 连接信息,包括host、port、user、password等信息
|
||||
* @param charset 编码
|
||||
* @param serverLanguageCode 服务器语言 例如:zh
|
||||
* @param systemKey 服务器标识 例如:org.apache.commons.net.ftp.FTPClientConfig.SYST_NT
|
||||
* @return CommonsFtp
|
||||
*/
|
||||
public static CommonsFtp of(final Connector connector, final Charset charset, final String serverLanguageCode, final String systemKey) {
|
||||
return of(connector, charset, serverLanguageCode, systemKey, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param connector 连接信息,包括host、port、user、password等信息
|
||||
* @param charset 编码
|
||||
* @param serverLanguageCode 服务器语言
|
||||
* @param systemKey 系统关键字
|
||||
* @param mode 模式
|
||||
* @return CommonsFtp
|
||||
*/
|
||||
public static CommonsFtp of(final Connector connector, final Charset charset, final String serverLanguageCode, final String systemKey, final FtpMode mode) {
|
||||
return new CommonsFtp(new FtpConfig(connector, charset, serverLanguageCode, systemKey), mode);
|
||||
}
|
||||
//endregion
|
||||
|
||||
private FTPClient client;
|
||||
private FtpMode mode;
|
||||
/**
|
||||
* 执行完操作是否返回当前目录
|
||||
*/
|
||||
private boolean backToPwd;
|
||||
|
||||
// region ----- 构造
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param config FTP配置
|
||||
* @param mode 模式
|
||||
*/
|
||||
public CommonsFtp(final FtpConfig config, final FtpMode mode) {
|
||||
super(config);
|
||||
this.mode = mode;
|
||||
this.init();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param client 自定义实例化好的{@link FTPClient}
|
||||
* @since 5.7.22
|
||||
*/
|
||||
public CommonsFtp(final FTPClient client) {
|
||||
super(FtpConfig.of());
|
||||
this.client = client;
|
||||
}
|
||||
// endregion
|
||||
|
||||
/**
|
||||
* 初始化连接
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public CommonsFtp init() {
|
||||
return this.init(this.ftpConfig, this.mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化连接
|
||||
*
|
||||
* @param config FTP配置
|
||||
* @param mode 模式
|
||||
* @return this
|
||||
*/
|
||||
public CommonsFtp 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.getConnector().getTimeout());
|
||||
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
|
||||
final Connector connector = config.getConnector();
|
||||
try {
|
||||
// 连接ftp服务器
|
||||
client.connect(connector.getHost(), connector.getPort());
|
||||
client.setSoTimeout((int) config.getSoTimeout());
|
||||
// 登录ftp服务器
|
||||
client.login(connector.getUser(), connector.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: [{}]", connector.getUser(), replyCode);
|
||||
}
|
||||
this.client = client;
|
||||
if (mode != null) {
|
||||
//noinspection resource
|
||||
setMode(mode);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置FTP连接模式,可选主动和被动模式
|
||||
*
|
||||
* @param mode 模式枚举
|
||||
* @return this
|
||||
* @since 4.1.19
|
||||
*/
|
||||
public CommonsFtp 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 CommonsFtp 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 CommonsFtp 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() {
|
||||
try {
|
||||
return client.printWorkingDirectory();
|
||||
} catch (final IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> ls(final String path) {
|
||||
return ArrayUtil.map(lsFiles(path), FTPFile::getName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 遍历某个目录下所有文件和目录,不会递归遍历<br>
|
||||
* 此方法自动过滤"."和".."两种目录
|
||||
*
|
||||
* @param path 目录
|
||||
* @param predicate 过滤器,null表示不过滤,默认去掉"."和".."两种目录
|
||||
* @return 文件名或目录名列表
|
||||
*/
|
||||
public List<String> ls(final String path, final Predicate<FTPFile> predicate) {
|
||||
return CollUtil.map(lsFiles(path, predicate), FTPFile::getName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 遍历某个目录下所有文件和目录,不会递归遍历<br>
|
||||
* 此方法自动过滤"."和".."两种目录
|
||||
*
|
||||
* @param path 目录
|
||||
* @param predicate 过滤器,null表示不过滤,默认去掉"."和".."两种目录
|
||||
* @return 文件或目录列表
|
||||
* @since 5.3.5
|
||||
*/
|
||||
public List<FTPFile> lsFiles(final String path, final Predicate<FTPFile> predicate) {
|
||||
final FTPFile[] ftpFiles = lsFiles(path);
|
||||
if (ArrayUtil.isEmpty(ftpFiles)) {
|
||||
return ListUtil.empty();
|
||||
}
|
||||
|
||||
final List<FTPFile> 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 遍历某个目录下所有文件和目录,不会递归遍历
|
||||
*
|
||||
* @param path 目录,如果目录不存在,抛出异常
|
||||
* @return 文件或目录列表
|
||||
* @throws FtpException 路径不存在
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取服务端目录状态。
|
||||
*
|
||||
* @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 文件路径
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件到指定目录,可选:
|
||||
*
|
||||
* <pre>
|
||||
* 1. remotePath为null或""上传到当前路径
|
||||
* 2. remotePath为相对路径则相对于当前路径的子路径
|
||||
* 3. remotePath为绝对路径则上传到此路径
|
||||
* </pre>
|
||||
*
|
||||
* @param remotePath 服务端路径,可以为{@code null} 或者相对路径或绝对路径
|
||||
* @param file 文件
|
||||
* @return 是否上传成功
|
||||
*/
|
||||
@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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件到指定目录,可选:
|
||||
*
|
||||
* <pre>
|
||||
* 1. remotePath为null或""上传到当前路径
|
||||
* 2. remotePath为相对路径则相对于当前路径的子路径
|
||||
* 3. remotePath为绝对路径则上传到此路径
|
||||
* </pre>
|
||||
*
|
||||
* @param file 文件
|
||||
* @param remotePath 服务端路径,可以为{@code null} 或者相对路径或绝对路径
|
||||
* @param fileName 自定义在服务端保存的文件名
|
||||
* @return 是否上传成功
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件到指定目录,可选:
|
||||
*
|
||||
* <pre>
|
||||
* 1. remotePath为null或""上传到当前路径
|
||||
* 2. remotePath为相对路径则相对于当前路径的子路径
|
||||
* 3. remotePath为绝对路径则上传到此路径
|
||||
* </pre>
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归上传文件(支持目录)<br>
|
||||
* 上传时,如果uploadFile为目录,只复制目录下所有目录和文件到目标路径下,并不会复制目录本身<br>
|
||||
* 上传时,自动创建父级目录
|
||||
*
|
||||
* @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<File> 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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客户端封装<br>
|
||||
* 此客户端基于Apache-Commons-Net
|
||||
* <p>
|
||||
* 常见搭建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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件或目录是否存在<br>
|
||||
* <ul>
|
||||
* <li>提供路径为空则返回{@code false}</li>
|
||||
* <li>提供路径非目录但是以'/'或'\'结尾返回{@code false}</li>
|
||||
* <li>文件名是'.'或者'..'返回{@code false}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @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<String> ls(final String path) {
|
||||
return ArrayUtil.map(lsFiles(path), FTPFile::getName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 遍历某个目录下所有文件和目录,不会递归遍历<br>
|
||||
* 此方法自动过滤"."和".."两种目录
|
||||
* 在当前远程目录(工作目录)下创建新的目录
|
||||
*
|
||||
* @param path 目录
|
||||
* @param predicate 过滤器,null表示不过滤,默认去掉"."和".."两种目录
|
||||
* @return 文件名或目录名列表
|
||||
* @param dir 目录名
|
||||
* @return 是否创建成功
|
||||
*/
|
||||
public List<String> ls(final String path, final Predicate<FTPFile> predicate) {
|
||||
return CollUtil.map(lsFiles(path, predicate), FTPFile::getName);
|
||||
}
|
||||
boolean mkdir(String dir);
|
||||
|
||||
/**
|
||||
* 遍历某个目录下所有文件和目录,不会递归遍历<br>
|
||||
* 此方法自动过滤"."和".."两种目录
|
||||
* 创建指定文件夹及其父目录,从根目录开始创建,创建完成后回到默认的工作目录
|
||||
*
|
||||
* @param path 目录
|
||||
* @param predicate 过滤器,null表示不过滤,默认去掉"."和".."两种目录
|
||||
* @return 文件或目录列表
|
||||
* @since 5.3.5
|
||||
* @param dir 文件夹路径,绝对路径
|
||||
*/
|
||||
public List<FTPFile> lsFiles(final String path, final Predicate<FTPFile> predicate) {
|
||||
final FTPFile[] ftpFiles = lsFiles(path);
|
||||
if (ArrayUtil.isEmpty(ftpFiles)) {
|
||||
return ListUtil.empty();
|
||||
}
|
||||
|
||||
final List<FTPFile> 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<String> 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);
|
||||
|
||||
/**
|
||||
* 上传文件到指定目录,可选:
|
||||
* 删除文件夹及其文件夹下的所有文件
|
||||
*
|
||||
* <pre>
|
||||
* 1. remotePath为null或""上传到当前路径
|
||||
* 2. remotePath为相对路径则相对于当前路径的子路径
|
||||
* 3. remotePath为绝对路径则上传到此路径
|
||||
* </pre>
|
||||
*
|
||||
* @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文件名相同。
|
||||
* 覆盖模式
|
||||
*
|
||||
* <pre>
|
||||
* 1. remotePath为null或""上传到当前路径
|
||||
* 2. remotePath为相对路径则相对于当前路径的子路径
|
||||
* 3. remotePath为绝对路径则上传到此路径
|
||||
* </pre>
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件到指定目录,可选:
|
||||
*
|
||||
* <pre>
|
||||
* 1. remotePath为null或""上传到当前路径
|
||||
* 2. remotePath为相对路径则相对于当前路径的子路径
|
||||
* 3. remotePath为绝对路径则上传到此路径
|
||||
* </pre>
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归上传文件(支持目录)<br>
|
||||
* 上传时,如果uploadFile为目录,只复制目录下所有目录和文件到目标路径下,并不会复制目录本身<br>
|
||||
* 上传时,自动创建父级目录
|
||||
*
|
||||
* @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<File> 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);
|
||||
}
|
||||
|
@ -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 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;
|
||||
/**
|
||||
* 设置超时,注意此方法会调用{@link Connector#setTimeout(long)}<br>
|
||||
* 此方法需在{@link #setConnector(Connector)}后调用,否则会创建空的Connector
|
||||
* @param timeout 链接超时
|
||||
* @return this
|
||||
*/
|
||||
public FtpConfig setConnectionTimeout(final long timeout){
|
||||
if(null == connector){
|
||||
connector = Connector.of();
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
|
@ -22,8 +22,13 @@ package org.dromara.hutool.extra.ftp;
|
||||
* @since 4.1.19
|
||||
*/
|
||||
public enum FtpMode {
|
||||
/** 主动模式 */
|
||||
|
||||
/**
|
||||
* 主动模式
|
||||
*/
|
||||
Active,
|
||||
/** 被动模式 */
|
||||
/**
|
||||
* 被动模式
|
||||
*/
|
||||
Passive
|
||||
}
|
||||
|
@ -13,16 +13,59 @@
|
||||
package org.dromara.hutool.extra.ssh;
|
||||
|
||||
/**
|
||||
* 连接者对象,提供一些连接的基本信息
|
||||
* 连接者对象,提供一些连接的基本信息,包括:
|
||||
* <ul>
|
||||
* <li>host:主机名</li>
|
||||
* <li>port:端口</li>
|
||||
* <li>user:用户名(默认root)</li>
|
||||
* <li>password:密码</li>
|
||||
* <li>timeout:连接超时毫秒数</li>
|
||||
* </ul>
|
||||
*
|
||||
* @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,31 +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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param host 主机名
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
@ -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 +
|
||||
'}';
|
||||
}
|
||||
|
@ -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,6 +133,7 @@ public class JschSftp extends AbstractFtp {
|
||||
init();
|
||||
}
|
||||
// ---------------------------------------------------------------------------------------- Constructor end
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
@ -140,12 +142,13 @@ public class JschSftp extends AbstractFtp {
|
||||
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();
|
||||
}
|
||||
|
||||
@ -159,7 +162,7 @@ public class JschSftp extends AbstractFtp {
|
||||
|
||||
try {
|
||||
if (!channel.isConnected()) {
|
||||
channel.connect((int) Math.max(this.ftpConfig.getConnectionTimeout(), 0));
|
||||
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 {
|
||||
@ -638,10 +641,11 @@ 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() + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
|
@ -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,6 +101,7 @@ public class SshjSftp extends AbstractFtp {
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param sshClient {@link SSHClient}
|
||||
* @param 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 {
|
||||
|
@ -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,7 +61,7 @@ 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());
|
||||
|
||||
@ -71,7 +71,7 @@ public class FtpTest {
|
||||
try {
|
||||
Console.log("打印pwd: " + ftp.pwd());
|
||||
} catch (final FtpException e) {
|
||||
e.printStackTrace();
|
||||
Console.error(e, e.getMessage());
|
||||
}
|
||||
|
||||
Console.log("判断是否超时并重连...");
|
||||
@ -85,7 +85,7 @@ public class FtpTest {
|
||||
@Test
|
||||
@Disabled
|
||||
public void recursiveDownloadFolder() {
|
||||
final Ftp ftp = new Ftp("looly.centos");
|
||||
final CommonsFtp ftp = CommonsFtp.of("looly.centos");
|
||||
ftp.recursiveDownloadFolder("/", FileUtil.file("d:/test/download"));
|
||||
|
||||
IoUtil.closeQuietly(ftp);
|
||||
@ -94,7 +94,7 @@ 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());
|
||||
@ -106,7 +106,7 @@ public class FtpTest {
|
||||
@Test
|
||||
@Disabled
|
||||
public void downloadTest() {
|
||||
final Ftp ftp = new Ftp("localhost");
|
||||
final CommonsFtp ftp = CommonsFtp.of("localhost");
|
||||
|
||||
final List<String> fileNames = ftp.ls("temp/");
|
||||
for (final String name : fileNames) {
|
||||
@ -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(""));
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user