
org.aoju.bus.extra.ftp.FtpUtils Maven / Gradle / Ivy
/*********************************************************************************
* *
* The MIT License *
* *
* Copyright (c) 2015-2020 aoju.org and other contributors. *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy *
* of this software and associated documentation files (the "Software"), to deal *
* in the Software without restriction, including without limitation the rights *
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell *
* copies of the Software, and to permit persons to whom the Software is *
* furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, *
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN *
* THE SOFTWARE. *
********************************************************************************/
package org.aoju.bus.extra.ftp;
import org.aoju.bus.core.lang.Assert;
import org.aoju.bus.core.lang.Symbol;
import org.aoju.bus.core.lang.exception.InstrumentException;
import org.aoju.bus.core.utils.ArrayUtils;
import org.aoju.bus.core.utils.FileUtils;
import org.aoju.bus.core.utils.ObjectUtils;
import org.aoju.bus.core.utils.StringUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
/**
* FTP客户端封装
* 此客户端基于Apache-Commons-Net
*
* @author Kimi Liu
* @version 5.6.9
* @since JDK 1.8+
*/
public class FtpUtils extends AbstractFtp {
/**
* 默认端口
*/
public static final int DEFAULT_PORT = 21;
private FTPClient client;
private FtpMode mode;
/**
* 构造,匿名登录
*
* @param host 域名或IP
*/
public FtpUtils(String host) {
this(host, DEFAULT_PORT);
}
/**
* 构造,匿名登录
*
* @param host 域名或IP
* @param port 端口
*/
public FtpUtils(String host, int port) {
this(host, port, "anonymous", "");
}
/**
* 构造
*
* @param host 域名或IP
* @param port 端口
* @param user 用户名
* @param password 密码
*/
public FtpUtils(String host, int port, String user, String password) {
this(host, port, user, password, org.aoju.bus.core.lang.Charset.UTF_8);
}
/**
* 构造
*
* @param host 域名或IP
* @param port 端口
* @param user 用户名
* @param password 密码
* @param charset 编码
*/
public FtpUtils(String host, int port, String user, String password, Charset charset) {
this(host, port, user, password, charset, null);
}
/**
* 构造
*
* @param host 域名或IP
* @param port 端口
* @param user 用户名
* @param password 密码
* @param charset 编码
* @param mode 模式
*/
public FtpUtils(String host, int port, String user, String password, Charset charset, FtpMode mode) {
this.host = host;
this.port = port;
this.user = user;
this.password = password;
this.charset = charset;
this.mode = mode;
this.init();
}
/**
* 初始化连接
*
* @return this
*/
public FtpUtils init() {
return this.init(this.host, this.port, this.user, this.password, this.mode);
}
/**
* 初始化连接
*
* @param host 域名或IP
* @param port 端口
* @param user 用户名
* @param password 密码
* @return this
*/
public FtpUtils init(String host, int port, String user, String password) {
return this.init(host, port, user, password, null);
}
/**
* 初始化连接
*
* @param host 域名或IP
* @param port 端口
* @param user 用户名
* @param password 密码
* @param mode 模式
* @return this
*/
public FtpUtils init(String host, int port, String user, String password, FtpMode mode) {
final FTPClient client = new FTPClient();
client.setControlEncoding(this.charset.toString());
try {
// 连接ftp服务器
client.connect(host, port);
// 登录ftp服务器
client.login(user, password);
} catch (IOException e) {
throw new InstrumentException(e);
}
final int replyCode = client.getReplyCode(); // 是否成功登录服务器
if (false == FTPReply.isPositiveCompletion(replyCode)) {
try {
client.disconnect();
} catch (IOException e) {
// ignore
}
throw new InstrumentException("Login failed for user [{" + user + "}], reply code is: [{" + replyCode + "}]");
}
this.client = client;
if (mode != null) {
setMode(mode);
}
return this;
}
/**
* 设置FTP连接模式,可选主动和被动模式
*
* @param mode 模式枚举
* @return this
*/
public FtpUtils setMode(FtpMode mode) {
this.mode = mode;
switch (mode) {
case Active:
this.client.enterLocalActiveMode();
break;
case Passive:
this.client.enterLocalPassiveMode();
break;
}
return this;
}
/**
* 如果连接超时的话,重新进行连接
* 经测试,当连接超时时,client.isConnected()仍然返回ture,无法判断是否连接超时
* 因此,通过发送pwd命令的方式,检查连接是否超时
*
* @return this
*/
@Override
public FtpUtils reconnectIfTimeout() {
String pwd = null;
try {
pwd = pwd();
} catch (InstrumentException fex) {
//ignore
}
if (pwd == null) {
return this.init();
}
return this;
}
/**
* 改变目录
*
* @param directory 目录
* @return 是否成功
*/
@Override
public boolean cd(String directory) {
boolean flag;
try {
flag = client.changeWorkingDirectory(directory);
} catch (IOException e) {
throw new InstrumentException(e);
}
return flag;
}
/**
* 远程当前目录
*
* @return 远程当前目录
*/
@Override
public String pwd() {
try {
return client.printWorkingDirectory();
} catch (IOException e) {
throw new InstrumentException(e);
}
}
@Override
public List ls(String path) {
final FTPFile[] ftpFiles = lsFiles(path);
final List fileNames = new ArrayList<>();
for (FTPFile ftpFile : ftpFiles) {
fileNames.add(ftpFile.getName());
}
return fileNames;
}
/**
* 遍历某个目录下所有文件和目录,不会递归遍历
*
* @param path 目录
* @return 文件或目录列表
*/
public FTPFile[] lsFiles(String path) {
String pwd = null;
if (StringUtils.isNotBlank(path)) {
pwd = pwd();
cd(path);
}
FTPFile[] ftpFiles;
try {
ftpFiles = this.client.listFiles();
} catch (IOException e) {
throw new InstrumentException(e);
}
if (StringUtils.isNotBlank(pwd)) {
// 回到原目录
cd(pwd);
}
return ftpFiles;
}
@Override
public boolean mkdir(String dir) {
boolean flag;
try {
flag = this.client.makeDirectory(dir);
} catch (IOException e) {
throw new InstrumentException(e);
}
return flag;
}
/**
* 判断ftp服务器文件是否存在
*
* @param path 文件路径
* @return 是否存在
*/
public boolean existFile(String path) {
FTPFile[] ftpFileArr;
try {
ftpFileArr = client.listFiles(path);
} catch (IOException e) {
throw new InstrumentException(e);
}
if (ArrayUtils.isNotEmpty(ftpFileArr)) {
return true;
}
return false;
}
@Override
public boolean delFile(String path) {
final String pwd = pwd();
final String fileName = FileUtils.getName(path);
final String dir = StringUtils.removeSuffix(path, fileName);
cd(dir);
boolean isSuccess;
try {
isSuccess = client.deleteFile(fileName);
} catch (IOException e) {
throw new InstrumentException(e);
}
cd(pwd);
return isSuccess;
}
@Override
public boolean delDir(String dirPath) {
FTPFile[] dirs;
try {
dirs = client.listFiles(dirPath);
} catch (IOException e) {
throw new InstrumentException(e);
}
String name;
String childPath;
for (FTPFile ftpFile : dirs) {
name = ftpFile.getName();
childPath = StringUtils.format("{}/{}", dirPath, name);
if (ftpFile.isDirectory()) {
// 上级和本级目录除外
if (false == ObjectUtils.equal(name, Symbol.DOT)
&& false == ObjectUtils.equal(name, Symbol.DOUBLE_DOT)) {
delDir(childPath);
}
} else {
delFile(childPath);
}
}
// 删除空目录
try {
return this.client.removeDirectory(dirPath);
} catch (IOException e) {
throw new InstrumentException(e);
}
}
/**
* 上传文件到指定目录,可选:
*
*
* 1. path为null或""上传到当前路径
* 2. path为相对路径则相对于当前路径的子路径
* 3. path为绝对路径则上传到此路径
*
*
* @param path 服务端路径,可以为{@code null} 或者相对路径或绝对路径
* @param file 文件
* @return 是否上传成功
*/
@Override
public boolean upload(String path, File file) {
Assert.notNull(file, "file to upload is null !");
return upload(path, file.getName(), file);
}
/**
* 上传文件到指定目录,可选:
*
*
* 1. path为null或""上传到当前路径
* 2. path为相对路径则相对于当前路径的子路径
* 3. path为绝对路径则上传到此路径
*
*
* @param file 文件
* @param path 服务端路径,可以为{@code null} 或者相对路径或绝对路径
* @param fileName 自定义在服务端保存的文件名
* @return 是否上传成功
*/
public boolean upload(String path, String fileName, File file) {
try (InputStream in = FileUtils.getInputStream(file)) {
return upload(path, fileName, in);
} catch (IOException e) {
throw new InstrumentException(e);
}
}
/**
* 上传文件到指定目录,可选:
*
*
* 1. path为null或""上传到当前路径
* 2. path为相对路径则相对于当前路径的子路径
* 3. path为绝对路径则上传到此路径
*
*
* @param path 服务端路径,可以为{@code null} 或者相对路径或绝对路径
* @param fileName 文件名
* @param fileStream 文件流
* @return 是否上传成功
*/
public boolean upload(String path, String fileName, InputStream fileStream) {
try {
client.setFileType(FTPClient.BINARY_FILE_TYPE);
} catch (IOException e) {
throw new InstrumentException(e);
}
if (StringUtils.isNotBlank(path)) {
mkDirs(path);
boolean isOk = cd(path);
if (false == isOk) {
return false;
}
}
try {
return client.storeFile(fileName, fileStream);
} catch (IOException e) {
throw new InstrumentException(e);
}
}
/**
* 下载文件
*
* @param path 文件路径
* @param outFile 输出文件或目录
*/
@Override
public void download(String path, File outFile) {
final String fileName = FileUtils.getName(path);
final String dir = StringUtils.removeSuffix(path, fileName);
download(dir, fileName, outFile);
}
/**
* 下载文件
*
* @param path 文件路径
* @param fileName 文件名
* @param outFile 输出文件或目录
*/
public void download(String path, String fileName, File outFile) {
if (outFile.isDirectory()) {
outFile = new File(outFile, fileName);
}
if (false == outFile.exists()) {
FileUtils.touch(outFile);
}
try (OutputStream out = FileUtils.getOutputStream(outFile)) {
download(path, fileName, out);
} catch (IOException e) {
throw new InstrumentException(e);
}
}
/**
* 下载文件到输出流
*
* @param path 文件路径
* @param fileName 文件名
* @param out 输出位置
*/
public void download(String path, String fileName, OutputStream out) {
cd(path);
try {
client.setFileType(FTPClient.BINARY_FILE_TYPE);
client.retrieveFile(fileName, out);
} catch (IOException e) {
throw new InstrumentException(e);
}
}
/**
* 获取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;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy