package org.dromara.system.uitil;
|
|
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.net.ftp.FTP;
|
import org.apache.commons.net.ftp.FTPClient;
|
import org.apache.commons.net.ftp.FTPFile;
|
import org.apache.commons.net.ftp.FTPReply;
|
import org.dromara.system.domain.properties.FtpConfig;
|
|
import java.io.*;
|
import java.net.UnknownHostException;
|
import java.text.SimpleDateFormat;
|
import java.util.ArrayList;
|
import java.util.List;
|
|
/**
|
* FTP工具类
|
*
|
* @author: simon
|
* @date: 2019/7/3 14:37
|
*/
|
public class FTPUtil {
|
/**
|
* 字符集
|
*/
|
private static final String DEFAULT_CHARSET = "UTF-8";
|
|
/**
|
* 超时时间
|
*/
|
private static final int DEFAULT_TIMEOUT = 60 * 1000;
|
|
/**
|
* 主机名或者ip地址
|
*/
|
private final String host;
|
|
/**
|
* ftp服务器端口
|
*/
|
private final int port;
|
|
/**
|
* ftp用户名
|
*/
|
private final String username;
|
|
/**
|
* ftp密码
|
*/
|
private final String password;
|
|
/**
|
* ftpClient对象
|
*/
|
private FTPClient ftpClient;
|
|
/**
|
* 初始化时ftp服务器路径
|
*/
|
private volatile String ftpBasePath = "";
|
|
/**
|
* 构造函数
|
*
|
* @param host 主机名或者ip地址
|
* @param username ftp 用户名
|
* @param password ftp 密码
|
* @param ftpBasePath 初始化时ftp服务器路径
|
*/
|
private FTPUtil(String host, String username, String password,String ftpBasePath) {
|
this(host, 21, username, password, DEFAULT_CHARSET,ftpBasePath);
|
setTimeout(DEFAULT_TIMEOUT, DEFAULT_TIMEOUT, DEFAULT_TIMEOUT);
|
}
|
|
/**
|
* 构造函数
|
*
|
// * @param host 主机名或者ip地址
|
// * @param username ftp 用户名
|
// * @param password ftp 密码
|
// * @param ftpBasePath 初始化时ftp服务器路径
|
*/
|
public FTPUtil(FtpConfig ftpConfig) {
|
this(ftpConfig.getUrl(), 21, ftpConfig.getUsername(), ftpConfig.getPasswd(), DEFAULT_CHARSET,ftpConfig.getPath());
|
setTimeout(DEFAULT_TIMEOUT, DEFAULT_TIMEOUT, DEFAULT_TIMEOUT);
|
}
|
|
/**
|
* 构造函数
|
*
|
* @param host 主机名或者ip地址
|
* @param port ftp 端口
|
* @param username 用户名
|
* @param password 密码
|
* @param ftpBasePath 初始化时ftp服务器路径
|
*/
|
private FTPUtil(String host, int port, String username, String password, String charset, String ftpBasePath) {
|
ftpClient = new FTPClient();
|
ftpClient.setControlEncoding(charset);
|
this.host = StringUtils.isEmpty(host) ? "localhost" : host;
|
this.port = (port <= 0) ? 21 : port;
|
this.username = StringUtils.isEmpty(username) ? "anonymous" : username;
|
this.password = password;
|
this.ftpBasePath = ftpBasePath;
|
}
|
|
/**
|
* 创建默认的ftp客户端
|
*
|
* @param host 主机名或者ip地址
|
* @param username ftp用户名
|
* @param password ftp密码
|
* @param ftpBasePath 初始化时ftp服务器路径
|
* @return com.siniswift.efb.acars.utils.FTPUtil
|
*/
|
public static FTPUtil createFtpCli(String host, String username, String password,String ftpBasePath) {
|
return new FTPUtil(host, username, password,ftpBasePath);
|
}
|
|
/**
|
* 创建自定义属性的ftp客户端
|
*
|
* @param host 主机名或者ip地址
|
* @param port ftp端口
|
* @param username ftp用户名
|
* @param password ftp密码
|
* @param charset 字符集
|
* @param ftpBasePath 初始化时ftp服务器路径
|
* @return com.siniswift.efb.acars.utils.FTPUtil
|
*/
|
public static FTPUtil createFtpCli(String host, int port, String username, String password, String charset,String ftpBasePath) {
|
return new FTPUtil(host, port, username, password, charset,ftpBasePath);
|
}
|
|
/**
|
* 设置超时时间
|
*
|
* @param defaultTimeout 超时时间
|
* @param connectTimeout 超时时间
|
* @param dataTimeout 超时时间
|
*/
|
private void setTimeout(int defaultTimeout, int connectTimeout, int dataTimeout) {
|
ftpClient.setDefaultTimeout(defaultTimeout);
|
ftpClient.setConnectTimeout(connectTimeout);
|
ftpClient.setDataTimeout(dataTimeout);
|
}
|
|
/**
|
* 连接到ftp
|
*/
|
public void connect() throws IOException {
|
try {
|
ftpClient.connect(host, port);
|
} catch (UnknownHostException e) {
|
throw new IOException("Can't find FTP server :" + host);
|
}
|
|
int reply = ftpClient.getReplyCode();
|
if (!FTPReply.isPositiveCompletion(reply)) {
|
disconnect();
|
throw new IOException("Can't connect to server :" + host);
|
}
|
|
if (!ftpClient.login(username, password)) {
|
disconnect();
|
throw new IOException("Can't login to server :" + host);
|
}
|
|
// set data transfer mode.
|
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
|
|
// Use passive mode to pass firewalls.
|
ftpClient.enterLocalPassiveMode();
|
|
initFtpBasePath();
|
}
|
|
/**
|
* 连接ftp时保存刚登陆ftp时的路径
|
*/
|
private void initFtpBasePath() throws IOException {
|
if (StringUtils.isEmpty(ftpBasePath)) {
|
synchronized (this) {
|
if (StringUtils.isEmpty(ftpBasePath)) {
|
ftpBasePath = ftpClient.printWorkingDirectory();
|
}
|
}
|
}
|
}
|
|
/**
|
* ftp是否处于连接状态,是连接状态返回<tt>true</tt>
|
*
|
* @return boolean 是连接状态返回<tt>true</tt>
|
*/
|
public boolean isConnected() {
|
return ftpClient.isConnected();
|
}
|
|
/**
|
* 上传文件到对应目录下
|
*
|
* @param fileName 文件名
|
* @param inputStream 文件输入流
|
* @param uploadDir 上传文件的父路径
|
* @return java.lang.String
|
*/
|
public String uploadFile(String fileName, InputStream inputStream, String uploadDir) throws IOException {
|
changeWorkingDirectory(ftpBasePath);
|
SimpleDateFormat dateFormat = new SimpleDateFormat("/yyyy/MM/dd");
|
makeDirs(uploadDir);
|
storeFile(fileName, inputStream);
|
return uploadDir + "/" + fileName;
|
}
|
|
/**
|
* 根据uploadFile返回的路径,从ftp下载文件到指定输出流中
|
*
|
* @param ftpRealFilePath 方法uploadFile返回的路径
|
* @param outputStream 输出流
|
*/
|
public void downloadFileFromDailyDir(String ftpRealFilePath, OutputStream outputStream) throws IOException {
|
changeWorkingDirectory(ftpBasePath);
|
ftpClient.retrieveFile(ftpRealFilePath, outputStream);
|
}
|
|
/**
|
* 获取ftp上指定文件名到输出流中
|
*
|
* @param ftpFileName 文件在ftp上的路径 如绝对路径 /home/ftpuser/123.txt 或者相对路径 123.txt
|
* @param out 输出流
|
*/
|
public void retrieveFile(String ftpFileName, OutputStream out) throws IOException {
|
try {
|
FTPFile[] fileInfoArray = ftpClient.listFiles(ftpFileName);
|
if (fileInfoArray == null || fileInfoArray.length == 0) {
|
throw new FileNotFoundException("File '" + ftpFileName + "' was not found on FTP server.");
|
}
|
|
FTPFile fileInfo = fileInfoArray[0];
|
if (fileInfo.getSize() > Integer.MAX_VALUE) {
|
throw new IOException("File '" + ftpFileName + "' is too large.");
|
}
|
|
if (!ftpClient.retrieveFile(ftpFileName, out)) {
|
throw new IOException("Error loading file '" + ftpFileName + "' from FTP server. Check FTP permissions and path.");
|
}
|
out.flush();
|
} finally {
|
closeStream(out);
|
}
|
}
|
|
|
/**
|
* 将输入流存储到指定的ftp路径下
|
*
|
* @param ftpFileName 文件在ftp上的路径 如绝对路径 /home/ftpuser/123.txt 或者相对路径 123.txt
|
* @param in 输入流
|
*/
|
private void storeFile(String ftpFileName, InputStream in) throws IOException {
|
try {
|
if (!ftpClient.storeFile(ftpFileName, in)) {
|
throw new IOException("Can't upload file '" + ftpFileName + "' to FTP server. Check FTP permissions and path.");
|
}
|
} finally {
|
closeStream(in);
|
}
|
}
|
|
/**
|
* 根据文件ftp路径名称删除文件
|
*
|
* @param ftpFileName 文件ftp路径名称
|
*/
|
public void deleteFile(String ftpFileName) throws IOException {
|
if (!ftpClient.deleteFile(ftpFileName)) {
|
throw new IOException("Can't remove file '" + ftpFileName + "' from FTP server.");
|
}
|
}
|
|
/**
|
* 上传文件到ftp
|
*
|
* @param ftpFileName 上传到ftp文件路径名称
|
* @param localFile 本地文件路径名称
|
*/
|
public void upload(String ftpFileName, File localFile) throws IOException {
|
if (!localFile.exists()) {
|
throw new IOException("Can't upload '" + localFile.getAbsolutePath() + "'. This file doesn't exist.");
|
}
|
|
InputStream in = null;
|
try {
|
in = new BufferedInputStream(new FileInputStream(localFile));
|
if (!ftpClient.storeFile(ftpFileName, in)) {
|
throw new IOException("Can't upload file '" + ftpFileName + "' to FTP server. Check FTP permissions and path.");
|
}
|
} finally {
|
closeStream(in);
|
}
|
}
|
|
/**
|
* 上传文件夹到ftp上
|
*
|
* @param remotePath ftp上文件夹路径名称
|
* @param localPath 本地上传的文件夹路径名称
|
*/
|
public void uploadDir(String remotePath, String localPath) throws IOException {
|
localPath = localPath.replace("\\\\", "/");
|
File file = new File(localPath);
|
if (file.exists()) {
|
if (!ftpClient.changeWorkingDirectory(remotePath)) {
|
ftpClient.makeDirectory(remotePath);
|
ftpClient.changeWorkingDirectory(remotePath);
|
}
|
File[] files = file.listFiles();
|
if (null != files) {
|
for (File f : files) {
|
if (f.isDirectory() && !f.getName().equals(".") && !f.getName().equals("..")) {
|
uploadDir(remotePath + "/" + f.getName(), f.getPath());
|
} else if (f.isFile()) {
|
upload(remotePath + "/" + f.getName(), f);
|
}
|
}
|
}
|
}
|
}
|
|
/**
|
* 下载ftp文件到本地上
|
*
|
* @param ftpFileName ftp文件路径名称
|
* @param localFile 本地文件路径名称
|
*/
|
public void download(String ftpFileName, File localFile) throws IOException {
|
OutputStream out = null;
|
try {
|
FTPFile[] fileInfoArray = ftpClient.listFiles(ftpFileName);
|
if (fileInfoArray == null || fileInfoArray.length == 0) {
|
throw new FileNotFoundException("File " + ftpFileName + " was not found on FTP server.");
|
}
|
|
FTPFile fileInfo = fileInfoArray[0];
|
if (fileInfo.getSize() > Integer.MAX_VALUE) {
|
throw new IOException("File " + ftpFileName + " is too large.");
|
}
|
|
out = new BufferedOutputStream(new FileOutputStream(localFile));
|
if (!ftpClient.retrieveFile(ftpFileName, out)) {
|
throw new IOException("Error loading file " + ftpFileName + " from FTP server. Check FTP permissions and path.");
|
}
|
out.flush();
|
} finally {
|
closeStream(out);
|
}
|
}
|
|
|
/**
|
* 改变工作目录
|
*
|
* @param dir ftp服务器上目录
|
* @return boolean 改变成功返回true
|
*/
|
public boolean changeWorkingDirectory(String dir) {
|
if (!ftpClient.isConnected()) {
|
return false;
|
}
|
try {
|
return ftpClient.changeWorkingDirectory(dir);
|
} catch (IOException e) {
|
e.printStackTrace();
|
}
|
return false;
|
}
|
|
/**
|
* 下载ftp服务器下文件夹到本地
|
*
|
* @param remotePath ftp上文件夹路径名称
|
* @param localPath 本地上传的文件夹路径名称
|
*/
|
public void downloadDir(String remotePath, String localPath) throws IOException {
|
localPath = localPath.replace("\\\\", "/");
|
File file = new File(localPath);
|
if (!file.exists()) {
|
file.mkdirs();
|
}
|
FTPFile[] ftpFiles = ftpClient.listFiles(remotePath);
|
for (int i = 0; ftpFiles != null && i < ftpFiles.length; i++) {
|
FTPFile ftpFile = ftpFiles[i];
|
if (ftpFile.isDirectory() && !ftpFile.getName().equals(".") && !ftpFile.getName().equals("..")) {
|
downloadDir(remotePath + "/" + ftpFile.getName(), localPath + "/" + ftpFile.getName());
|
} else {
|
download(remotePath + "/" + ftpFile.getName(), new File(localPath + "/" + ftpFile.getName()));
|
}
|
}
|
}
|
|
|
/**
|
* 列出ftp上文件目录下的文件
|
*
|
* @param filePath ftp上文件目录
|
* @return java.util.List<java.lang.String>
|
*/
|
public List<String> listFileNames(String filePath) throws IOException {
|
FTPFile[] ftpFiles = ftpClient.listFiles(filePath);
|
List<String> fileList = new ArrayList<>();
|
if (ftpFiles != null) {
|
for (int i = 0; i < ftpFiles.length; i++) {
|
FTPFile ftpFile = ftpFiles[i];
|
if (ftpFile.isFile()) {
|
fileList.add(ftpFile.getName());
|
}
|
}
|
}
|
|
return fileList;
|
}
|
|
/**
|
* 发送ftp命令到ftp服务器中
|
*
|
* @param args ftp命令
|
*/
|
public void sendSiteCommand(String args) throws IOException {
|
if (!ftpClient.isConnected()) {
|
ftpClient.sendSiteCommand(args);
|
}
|
}
|
|
/**
|
* 获取当前所处的工作目录
|
*
|
* @return java.lang.String 当前所处的工作目录
|
*/
|
public String printWorkingDirectory() {
|
if (!ftpClient.isConnected()) {
|
return "";
|
}
|
try {
|
return ftpClient.printWorkingDirectory();
|
} catch (IOException e) {
|
// do nothing
|
}
|
|
return "";
|
}
|
|
/**
|
* 切换到当前工作目录的父目录下
|
*
|
* @return boolean 切换成功返回true
|
*/
|
public boolean changeToParentDirectory() {
|
|
if (!ftpClient.isConnected()) {
|
return false;
|
}
|
|
try {
|
return ftpClient.changeToParentDirectory();
|
} catch (IOException e) {
|
// do nothing
|
}
|
|
return false;
|
}
|
|
/**
|
* 返回当前工作目录的上一级目录
|
*
|
* @return java.lang.String 当前工作目录的父目录
|
*/
|
public String printParentDirectory() {
|
if (!ftpClient.isConnected()) {
|
return "";
|
}
|
|
String w = printWorkingDirectory();
|
changeToParentDirectory();
|
String p = printWorkingDirectory();
|
changeWorkingDirectory(w);
|
|
return p;
|
}
|
|
/**
|
* 创建目录
|
*
|
* @param pathname 路径名
|
* @return boolean 创建成功返回true
|
*/
|
public boolean makeDirectory(String pathname) throws IOException {
|
return ftpClient.makeDirectory(pathname);
|
}
|
|
/**
|
* 创建多个目录
|
*
|
* @param pathname 路径名
|
*/
|
public void makeDirs(String pathname) throws IOException {
|
pathname = pathname.replace("\\\\", "/");
|
String[] pathnameArray = pathname.split("/");
|
for (String each : pathnameArray) {
|
if (StringUtils.isNotEmpty(each)) {
|
ftpClient.makeDirectory(each);
|
ftpClient.changeWorkingDirectory(each);
|
}
|
}
|
}
|
|
/**
|
* 关闭流
|
*
|
* @param stream 流
|
*/
|
private static void closeStream(Closeable stream) {
|
if (stream != null) {
|
try {
|
stream.close();
|
} catch (IOException ex) {
|
// do nothing
|
}
|
}
|
}
|
|
/**
|
* 关闭ftp连接
|
*/
|
public void disconnect() {
|
if (null != ftpClient && ftpClient.isConnected()) {
|
try {
|
ftpClient.logout();
|
ftpClient.disconnect();
|
} catch (IOException ex) {
|
// do nothing
|
}
|
}
|
}
|
}
|