build.gradle
group 'com.aiuyo'
version '1.0-SNAPSHOT'
apply plugin: 'java'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
// https://mvnrepository.com/artifact/commons-net/commons-net
compile group: 'commons-net', name: 'commons-net', version: '3.6'
// https://mvnrepository.com/artifact/log4j/log4j
compile group: 'log4j', name: 'log4j', version: '1.2.17'
// https://mvnrepository.com/artifact/commons-io/commons-io
compile group: 'commons-io', name: 'commons-io', version: '2.5'
// https://mvnrepository.com/artifact/org.apache.commons/commons-lang3
compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.6'
testCompile group: 'junit', name: 'junit', version: '4.12'
}
FtpClientUtil
package com.aiuyo.util.ftpclientutil;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.log4j.Logger;
import java.io.*;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;
/**
* FtpClientUtil
* 功能说明:FTP客户端
* @author WangXianfeng"wang-xianfeng@qq.com" 2017/7/21 16:25
**/
public class FtpClientUtil {
private static final Logger logger = Logger.getLogger(FtpClientUtil.class);
private static String encoding = "GBK";
private static FTPClient client;
/** ftp服务器地址 */
private String host;
/** ftp 端口号 默认21 */
private int port = 21;
/** ftp服务器用户名 */
private String username;
/** ftp服务器密码 */
private String password;
/** ftp远程目录 */
private String remoteDir;
/** 本地存储目录 */
private String localPath;
/** 文件路径通配符 默认列出所有 */
private String regEx = "*";
/** 指定要下载的文件名 */
private String downloadFileName;
/**
* 功能说明:构造函数,默认21端口
* @param host FTP主机IP
* @param username FTP用户名
* @param password FTP密码
* @return
* @author WangXianfeng"wang-xianfeng@qq.com"
*/
public FtpClientUtil(String host, String username, String password){
this.host = host;
this.username = username;
this.password = password;
}
/**
* 功能说明:构造函数,指定FTP端口
* @param host FTP主机IP
* @param port FTP端口
* @param username FTP用户名
* @param password FTP密码
* @return
* @author WangXianfeng"wang-xianfeng@qq.com"
*/
public FtpClientUtil(String host, int port, String username, String password){
this.host = host;
this.port = port;
this.username = username;
this.password = password;
}
/**
* 功能说明:连接FTP
* @param
* @return boolean
* @author WangXianfeng"wang-xianfeng@qq.com" 2017/7/21 17:22
*/
public boolean connectServer() {
boolean connected = false;
client = new FTPClient();
// 设置超时时间
client.setConnectTimeout(30000);
try {
//连接服务器
if (!client.isConnected()) {
//连接FTP
client.connect(host, port);
// 登录
client.login(username, password);
// 获取ftp登录应答码
int reply = client.getReplyCode();
// 验证是否登陆成功
if (!FTPReply.isPositiveCompletion(reply)) {
logger.info("未连接到FTP,用户名或密码错误。");
client.disconnect();
} else {
//设置连接属性
client.setControlEncoding(encoding);
// 设置以二进制方式传输
client.setFileType(FTPClient.BINARY_FILE_TYPE);
client.enterLocalPassiveMode();
logger.info("FTP连接成功。IP:" + host + ",PORT:" + port);
connected = true;
}
}
} catch (SocketException e) {
try {
client.disconnect();
} catch (IOException e1) {
}
logger.error("连接FTP服务器失败" + e.getMessage());
throw new RuntimeException("连接FTP服务器失败" + e.getMessage());
} catch (IOException e) {
try {
client.disconnect();
} catch (IOException e1) {
}
logger.error("连接FTP服务器失败" + e.getMessage());
throw new RuntimeException("连接FTP服务器失败" + e.getMessage());
}
return connected;
}
/**
* 功能说明:根据路径递归列返回文件列表
* @param remotePath 远程FTP路径
* @return java.util.List<java.lang.String> 文件列表
* @author WangXianfeng"wang-xianfeng@qq.com" 2017/7/21 17:31
*/
public List<String> listAllFiles(String remotePath){
List<String> ftpFilePaths = new ArrayList<>();
//是否连接服务器标识
boolean isConnected = false;
//如果未连接服务器,则调用connectServer方法连接
if(null==this.client||!this.client.isConnected()){
isConnected = this.connectServer();
}else{
isConnected = this.client.isConnected();
}
//如果已经连接,则列出文件
if(isConnected){
//递归获取远程FTP上的所有文件路径
try {
logger.info("Listing directory:" + remotePath);
if(remotePath.endsWith("/")){
remotePath = remotePath.substring(0,remotePath.length() - 1);
}
FTPFile[] files = this.client.listFiles(remotePath);
for (FTPFile file:files) {
if (file.isFile()) {
ftpFilePaths.add(remotePath + "/" + file.getName());
} else if (file.isDirectory()) {
//如果是目录,递归调用该方法返回该目录下的文件
List<String> subList = listAllFiles(
remotePath + "/" + file.getName());
ftpFilePaths.addAll(subList);
}
}
} catch (IOException e) {
logger.error("发生IO异常",e);
}
}
logger.info("List ftp file done");
return ftpFilePaths;
}
/**
* 功能说明:下载单个FTP文件到本地
* @param localPath 本地文件路径
* @param localFileName 本地文件名称,留空则与远程文件保持一致
* @param remotePath FTP路径
* @param remoteFileName FTP文件名称
* @return boolean
* @author WangXianfeng"wang-xianfeng@qq.com" 2017/7/21 17:54
*/
public boolean downloadFile(String localPath,String localFileName,String remotePath,String remoteFileName)throws Exception{
boolean successFlag = false;
//是否连接服务器标识
boolean isConnected = false;
//如果未连接服务器,则调用connectServer方法连接
if(null==this.client||!this.client.isConnected()){
isConnected = this.connectServer();
}else{
isConnected = this.client.isConnected();
}
if(isConnected){
File downloadFile = null;
try {
//检查输入参数
checkParams("download",localPath,localFileName,remotePath,remoteFileName);
//设置远程FTP目录
if(StringUtils.isEmpty(remotePath)){
remotePath = this.remoteDir;
}
if(remotePath.endsWith("/")){
remotePath = remotePath.substring(0,remotePath.length() - 1);
}
client.changeWorkingDirectory(remotePath);
logger.info("切换至工作目录【" + remotePath + "】成功");
//读取远程文件
FTPFile[] ftpFiles = client.listFiles();
if (ftpFiles.length == 0) {
logger.warn("文件数为0,没有可下载的文件!");
successFlag = false;
}
logger.info("准备下载" + ftpFiles.length + "个文件");
// 3、保存文件到本地
for (FTPFile file : ftpFiles) {
if(file.isFile()) {
logger.debug("正在保存文件:" + remotePath + "/" + file.getName() + "至本地");
//指定下载的文件
if (StringUtils.isNotBlank(remoteFileName) && !file.getName().equals(remoteFileName)) {
continue;
}
if(StringUtils.isEmpty(localPath)){
localPath = this.getLocalPath();
}
if(StringUtils.isEmpty(localFileName)){
localPath = localPath + File.separator + file.getName();
}else{
localPath = localPath + File.separator + localFileName;
}
downloadFile = new File(localPath);
OutputStream os = new FileOutputStream(downloadFile);
client.retrieveFile(file.getName(), os);
IOUtils.closeQuietly(os);
logger.info("文件下载成功,文件路径:" + localPath);
successFlag = true;
}
}
} catch (Exception e) {
logger.error("下载文件失败" + e.getMessage());
throw new RuntimeException("下载文件失败" + e.getMessage());
}
}
return successFlag;
}
/**
* 功能说明:检查下载文件的输入参数是否合法
* @param localPath
* @param localFileName
* @param remotePath
* @param remoteFileName
* @return void
* @throws Exception
* @author WangXianfeng"wang-xianfeng@qq.com" 2017-07-22 06:33:44
*/
private void checkParams(String operType,String localPath, String localFileName,
String remotePath, String remoteFileName) throws Exception{
if(StringUtils.isEmpty(this.localPath)&&StringUtils.isEmpty(localPath)){
throw new Exception("未指定本地目录");
}
if(StringUtils.isEmpty(this.remoteDir)&&StringUtils.isEmpty(remotePath)){
throw new Exception("未指定FTP远程目录");
}
if(!StringUtils.isEmpty(operType)&&"download".equals(operType)){
if(StringUtils.isEmpty(remoteFileName)){
throw new Exception("未指定下载文件名");
}
}
if(!StringUtils.isEmpty(operType)&&"upload".equals(operType)){
if(StringUtils.isEmpty(localFileName)){
throw new Exception("未指定本地上传文件名");
}
}
}
/**
* 功能说明:上传本地单个文件到远程目录
* @param localPath
* @param localFileName
* @param remotePath
* @param remoteFileName
* @return boolean
* @throws
* @author WangXianfeng"wang-xianfeng@qq.com" 2017-07-22 07:17:45
*/
public boolean uploadFile(String localPath,String localFileName,String remotePath,String remoteFileName)throws Exception{
boolean successFlag = false;
//是否连接服务器标识
boolean isConnected = false;
//如果未连接服务器,则调用connectServer方法连接
if(null==this.client||!this.client.isConnected()){
isConnected = this.connectServer();
}else{
isConnected = this.client.isConnected();
}
if(isConnected){
//检查输入参数
checkParams("upload",localPath,localFileName,remotePath,remoteFileName);
//设置远程FTP目录
if(StringUtils.isEmpty(remotePath)){
remotePath = this.remoteDir;
}
if(remotePath.endsWith("/")){
remotePath = remotePath.substring(0,remotePath.length() - 1);
}
client.changeWorkingDirectory(remotePath);
logger.info("切换至工作目录【" + remotePath + "】成功");
try {
//准备本地需要上传的文件
if(StringUtils.isEmpty(localPath)){
localPath = this.getLocalPath();
}
localPath = localPath + File.separator + localFileName;
File localFile = new File(localPath);
OutputStream os = null;
os = client.storeFileStream(localFile.getName());
if (os == null){
throw new RuntimeException("上传失败,请检查是否有上传权限");
}
IOUtils.copy(new FileInputStream(localFile), os);
IOUtils.closeQuietly(os);
logger.info("文件上传成功,上传文件路径:" + remotePath + "/" + localFile.getName());
}catch (Exception e){
logger.error("上传文件失败" + e.getMessage());
throw new RuntimeException("上传文件失败" + e.getMessage());
}
}
return successFlag;
}
/**
* 功能说明:下载远程目录所有的文件到本地目录
* @param localPath
* @param remotePath
* @return java.util.List<java.lang.String> 本地文件列表
* @throws
* @author WangXianfeng"wang-xianfeng@qq.com" 2017-07-22 08:10:40
*/
public List<String> downloadDirectory(String localPath,String remotePath)throws Exception {
List<String> localFilePathList = new ArrayList<>();
//是否连接服务器标识
boolean isConnected = false;
//如果未连接服务器,则调用connectServer方法连接
if (null == this.client || !this.client.isConnected()) {
isConnected = this.connectServer();
} else {
isConnected = this.client.isConnected();
}
if (isConnected) {
try {
logger.info("正在下载远程目录:" + remotePath + "到本地目录:" + localPath);
//检查输入参数
if(StringUtils.isEmpty(this.localPath)&&StringUtils.isEmpty(localPath)){
throw new Exception("未指定本地目录");
}
if(StringUtils.isEmpty(this.remoteDir)&&StringUtils.isEmpty(remotePath)){
throw new Exception("未指定FTP远程目录");
}
//设置远程FTP目录
if (StringUtils.isEmpty(remotePath)) {
remotePath = this.remoteDir;
}
if (remotePath.endsWith("/")) {
remotePath = remotePath.substring(0, remotePath.length() - 1);
}
client.changeWorkingDirectory(remotePath);
logger.info("切换至工作目录【" + remotePath + "】成功");
//读取远程文件
FTPFile[] ftpFiles = client.listFiles();
if (ftpFiles.length == 0) {
logger.warn("文件数为0,没有可下载的文件!");
return localFilePathList;
}
logger.info("准备下载" + ftpFiles.length + "个文件");
String localFilePath = null;
//保存文件到本地
for (FTPFile file : ftpFiles) {
if (file.isFile()) {
logger.debug("正在保存文件:" + remotePath + "/" + file.getName() + "至本地");
if (StringUtils.isEmpty(localPath)) {
localPath = this.getLocalPath();
}
File localDir = new File(localPath);
if(!localDir.exists()){
localDir.mkdir();
}
localFilePath = localPath + File.separator + file.getName();
File downloadFile = new File(localFilePath);
OutputStream os = new FileOutputStream(downloadFile);
client.retrieveFile(file.getName(), os);
IOUtils.closeQuietly(os);
logger.info("文件下载成功,文件路径:" + localFilePath);
localFilePathList.add(localPath);
}else if(file.isDirectory()){
localPath += File.separator + file.getName();
remotePath += "/" + file.getName();
List<String> subDirPathList = this.downloadDirectory(localPath,remotePath);
localFilePathList.addAll(subDirPathList);
}
}
} catch (Exception e) {
logger.error("下载文件失败" + e.getMessage());
throw new RuntimeException("下载文件失败" + e.getMessage());
}
}
return localFilePathList;
}
/**
* 功能说明:关闭FTP连接
* @param
* @return void
* @throws
* @author WangXianfeng"wang-xianfeng@qq.com" 2017-07-22 08:09:23
*/
public void closeConnect() {
try {
client.disconnect();
logger.info(" 关闭FTP连接成功!!! ");
} catch (IOException e) {
logger.warn(" 关闭FTP连接失败!!! ", e);
}
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRemoteDir() {
return remoteDir;
}
public void setRemoteDir(String remoteDir) {
this.remoteDir = remoteDir;
}
public String getLocalPath() {
return localPath;
}
public void setLocalPath(String localPath) {
this.localPath = localPath;
}
public String getRegEx() {
return regEx;
}
public void setRegEx(String regEx) {
this.regEx = regEx;
}
public String getDownloadFileName() {
return downloadFileName;
}
public void setDownloadFileName(String downloadFileName) {
this.downloadFileName = downloadFileName;
}
}
文章评论