FtpClientUtil

2017-07-22 1359点热度 0人点赞 0条评论

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;
    }
}

 

 

 

王显锋

激情工作,快乐生活!

文章评论