java FTPClient实现的FTP上传工具类

女人如花 发表于:2018-09-03 15:35 阅读: 282次

今天在开发项目过程中,遇到了将TOMCAT服务器上的图片,上传到专门的文件存储服务器上,文件存储服务器开放了FTP服务,下面记录下基于java的FTPClient开发的FTP上传工具类,以便以后使用。

工具类代码

package com.kumapai.framework.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.net.SocketException;

import org.apache.commons.net.PrintCommandListener;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPConnectionClosedException;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

import com.xiangxun.atms.framework.log.Logging;

/*******************************************************************************
 * ftp客户端操作工具类
 * @author kumapai.com
 */
public class FtpClientUtils {
    private Logging logger = new Logging(FtpClientUtils.class);
    private FTPClient ftpClient = null;
    private String ip;
    private String username;
    private String password;
    private int port;
    private boolean showCommand = false;

    public FtpClientUtils(String ip, String username, String password, int port) {
        this.ip = ip;
        this.username = username;
        this.password = password;
        this.port = port;
    }

    /***************************************************************************
     * 上传文件,需要手工打开和关闭连接
     * 
     * @param remote
     *            远程目录
     * @param local
     *            本地文件
     */
    public void storeFileNew(String remote, String local) {
        InputStream input = null;
        try {
            createDirecroty(remote,this.ftpClient);
            input = new FileInputStream(local);
        } catch (FileNotFoundException e) {
            logger.error("file not found:" + local);
        } catch (IOException e) {
            logger.error(e);
        }
        int lastIndexOf = local.lastIndexOf("\\");
        String imgName = local.substring(lastIndexOf + 1,local.length());
        if (input != null) {
            try {
                ftpClient.changeWorkingDirectory(remote);
                ftpClient.storeFile(imgName, input);
                input.close();
            } catch (IOException e) {
                e.printStackTrace();
                logger.error(e);
            }
        }
    }

    /***************************************************************************
     * 上传文件,需要手工打开和关闭连接
     * 
     * @param remote
     *            远程目录
     * @param local
     *            本地文件
     */
    public void storeFile(String remote, String local) {
        InputStream input = null;
        try {
            createDirecroty(remote);
            input = new FileInputStream(local);
        } catch (FileNotFoundException e) {
            logger.error("file not found:" + local);
        } catch (IOException e) {
            logger.error(e);
        }
        if (input != null) {
            try {
                ftpClient.storeFile(remote, input);
                input.close();
            } catch (IOException e) {
                e.printStackTrace();
                logger.error(e);
            }
        }
    }

    /***************************************************************************
     * 上传文件,需要手工打开和关闭连接
     * 
     * @param input
     * @param remote
     * @return
     */
    public boolean storeFile(InputStream input, String remote) {
        if (input != null) {
            try {
                return ftpClient.storeFile(remote, input);
            } catch (IOException e) {
                e.printStackTrace();
                logger.error(e);
                return false;
            }finally{
                if (input != null) {
                    try {
                        input.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return false;
    }

    /***************************************************************************
     * 获取文件列表
     * 
     * @param remote
     * @return
     */
    public FTPFile[] listFiles(String remote) {
        try {
            // 打开连接
            open();
            try {
                return ftpClient.listFiles(remote);
            } catch (IOException e) {
                e.printStackTrace();
                logger.error(e);
                return null;
            }
        } finally {
            // 关闭连接
            close();
        }
    }

    /***************************************************************************
     * list file details using MLST
     */
    public FTPFile mlistFile(String remote) {
        try {
            // 打开连接
            open();
            try {
                return ftpClient.mlistFile(remote);
            } catch (IOException e) {
                e.printStackTrace();
                logger.error(e);
                return null;
            }
        } finally {
            // 关闭连接
            close();
        }
    }

    /***************************************************************************
     * listNames
     */
    public String[] listNames(String remote) {
        try {
            // 打开连接
            open();
            try {
                return ftpClient.listNames(remote);
            } catch (IOException e) {
                e.printStackTrace();
                logger.error(e);
                return null;
            }
        } finally {
            // 关闭连接
            close();
        }
    }

    /***************************************************************************
     * list directory details using MLSD
     * 
     * @param remote
     * @return
     */
    public FTPFile[] listDir(String remote) {
        try {
            // 打开连接
            open();
            try {
                return ftpClient.mlistDir(remote);
            } catch (IOException e) {
                e.printStackTrace();
                logger.error(e);
                return null;
            }
        } finally {
            // 关闭连接
            close();
        }
    }

    /***
     * 调用完成后,要调用    ftpClientUtils.completeStream(),否则可能出现ftp连接僵死。
     * @param remote
     * @return
     */
    public InputStream loadtoInputStream(String remote) {
        try {
            // 打开连接
            open();
            return ftpClient.retrieveFileStream(remote);
        } catch (IOException e) {
            e.printStackTrace();
            logger.error(e);
            return null;
        }

    }


    public boolean completeStream(){
        try {
            return ftpClient.completePendingCommand();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 上传文件到FTP服务器,支持断点续传
     * 
     * @param local
     *            本地文件名称,绝对路径
     * @param remote
     *            远程文件路径,使用/home/directory1/subdirectory/file.ext
     *            按照Linux上的路径指定方式,支持多级目录嵌套,支持递归创建不存在的目录结构
     * @return 上传结果
     * @throws IOException
     */
    public UploadStatus upload(File localFile, String remote) throws IOException {
        try {
            // 打开连接
            open();
            UploadStatus result;
            // 对远程目录的处理
            String remoteFileName = remote;
            if (remote.contains("/")) {
                String directory = remote.substring(0,remote.lastIndexOf("/") + 1);
                // 创建服务器远程目录结构,创建失败直接返回
                try {
                    createDirecroty(directory, ftpClient);
                } catch (IOException e) {
                    logger.error(e);
                    return UploadStatus.CREATE_DIRECTORY_FAIL;
                }
            }

            // 检查远程是否存在文件
            FTPFile[] files = ftpClient.listFiles(remoteFileName);

            if (files != null && files.length == 1) {
                long remoteSize = files[0].getSize();
                // File f = new File(local);
                long localSize = localFile.length();
                if (remoteSize == localSize) {
                    return UploadStatus.FILE_EXITS;
                } else if (remoteSize > localSize) {
                    return UploadStatus.REMOTE_BIGGER_LOCAL;
                }
                // 尝试移动文件内读取指针,实现断点续传
                result = uploadFile(remoteFileName, localFile, ftpClient, remoteSize);
                // 如果断点续传没有成功,则删除服务器上文件,重新上传
                if (result == UploadStatus.UPLOAD_FROM_BREAK_FAILED) {
                    if (!ftpClient.deleteFile(remoteFileName)) {
                        return UploadStatus.DELETE_REMOTE_FAILD;
                    }
                    result = uploadFile(remoteFileName, localFile, ftpClient, 0);
                }
            } else {
                result = uploadFile(remoteFileName, localFile, ftpClient, 0);
            }
            return result;
        } finally {
            // 关闭连接
            close();
        }
    }

    /**
     * 上传文件到服务器,新上传和断点续传
     * 
     * @param remoteFile
     *            远程文件名,在上传之前已经将服务器工作目录做了改变
     * @param localFile
     *            本地文件File句柄,绝对路径
     * @param processStep
     *            需要显示的处理进度步进值
     * @param ftpClient
     *            FTPClient引用
     * @return
     * @throws IOException
     */
    private UploadStatus uploadFile(String remoteFile, File localFile, FTPClient ftpClient, long remoteSize) throws IOException {
        UploadStatus status;
        // 显示进度的上传
        long step = localFile.length() / 100;
        long process = 0;
        long localreadbytes = 0L;
        RandomAccessFile raf = new RandomAccessFile(localFile, "r");
        OutputStream out = ftpClient.appendFileStream(remoteFile);
        // 断点续传
        if (remoteSize > 0) {
            ftpClient.setRestartOffset(remoteSize);
            process = remoteSize / step;
            raf.seek(remoteSize);
            localreadbytes = remoteSize;
        }
        byte[] bytes = new byte[64*1024];
        int c;
        while ((c = raf.read(bytes)) != -1) {
            out.write(bytes, 0, c);
            localreadbytes += c;
            if (localreadbytes / step != process) {
                process = localreadbytes / step;
            }
        }
        out.flush();
        raf.close();
        out.close();
        boolean result = ftpClient.completePendingCommand();
        if (remoteSize > 0) {
            status = result ? UploadStatus.UPLOAD_FROM_BREAK_SUCCESS : UploadStatus.UPLOAD_FROM_BREAK_FAILED;
        } else {
            status = result ? UploadStatus.UPLOAD_NEW_FILE_SUCCESS : UploadStatus.UPLOAD_NEW_FILE_FAILED;
        }
        return status;
    }

    /**
     * 功能:创建目录 若传入路径已经存在,则返回该路径,否则创建 目前暂不支持中文列名
     * 
     * @param remoteDir
     * @return
     * @throws IOException
     *             String 范例:
     */
    public String createDirecroty(String remoteDir) throws IOException {
        String fillDir = "";
        try {
            // 打开连接
            open();
            createDirecroty(remoteDir, this.ftpClient);
            fillDir = remoteDir;
        } catch (IOException e) {
            return fillDir;
        } finally {
            // 关闭连接
            close();
        }
        return fillDir;
    }

    /**
     * 级联创建目录
     * @throws IOException
     * @throws SocketException
     */
    public void createDirecroty(String folderPath, FTPClient ftpClient) throws IOException {
        logger.info("正在创建目录");
        if (folderPath == null || "".equals(folderPath)) {
            return;
        }
        String directory = folderPath.substring(0,folderPath.lastIndexOf("/")+1);  
        String separate = directory.indexOf("/") > 0 ? "/" : "\\\\";// 路径中使用的下一级文件夹的分隔符,java中用split方法用"\\\\"来当"\"分隔
        String[] pathL = directory.split(separate);
        String path = "";
        for (String string : pathL) {
            path += path.length() > 0 ? "/" + string : string;
            ftpClient.makeDirectory(path);
        }
    }

    public void open() {
        ftpClient =  new FTPClient();
        ftpClient.setControlEncoding("UTF-8");
        ftpClient.setBufferSize(64*1024);
        ftpClient.enterLocalPassiveMode();
        // 是否显示操作详细信息
        if (showCommand) {
            ftpClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out), true));
        }
        try {
            int reply;
            if (port > 0) {
                ftpClient.connect(ip, port);
            } else {
                ftpClient.connect(ip);
            }
            logger.debug("Connected to " + ip + " on  21");
            // After connection attempt, you should check the reply code to
            // verify
            // success.
            reply = ftpClient.getReplyCode();

            if (!FTPReply.isPositiveCompletion(reply)) {
                ftpClient.disconnect();
                logger.error("FTP server refused connection.");
            }

            if (!ftpClient.login(username, password)) {
                ftpClient.logout();
                return;
            }
            // 设置为二进制传输
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);

        } catch (IOException e) {
            if (ftpClient.isConnected()) {
                try {
                    ftpClient.disconnect();
                } catch (IOException f) {
                }
            }
            return;
        }
    }

    public void close() {
        try {
            if(ftpClient.isConnected()){
                ftpClient.noop();
                ftpClient.logout();
            }
        } catch (FTPConnectionClosedException e) {
            logger.error("Server closed connection.");
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ftpClient.isConnected()) {
                try {
                    ftpClient.disconnect();
                } catch (IOException f) {
                    f.printStackTrace();
                }
            }
        }
    }

    public void setShowCommand(boolean showCommand) {
        this.showCommand = showCommand;
    }

    // 枚举上传状态
    public enum UploadStatus {
        CREATE_DIRECTORY_FAIL, // 远程服务器相应目录创建失败
        CREATE_DIRECTORY_SUCCESS, // 远程服务器创建目录成功
        UPLOAD_NEW_FILE_SUCCESS, // 上传新文件成功
        UPLOAD_NEW_FILE_FAILED, // 上传新文件失败
        FILE_EXITS, // 文件已经存在
        REMOTE_BIGGER_LOCAL, // 远程文件大于本地文件
        UPLOAD_FROM_BREAK_SUCCESS, // 断点续传成功
        UPLOAD_FROM_BREAK_FAILED, // 断点续传失败
        DELETE_REMOTE_FAILD; // 删除远程文件失败
    }

    public static void main(String[] args) {
        FtpClientUtils ftpClientUtils = new FtpClientUtils("193.169.100.183", "xiangxun", "88151312", 21);
        ftpClientUtils.setShowCommand(true);
//        try {
//            File files = new File("C:/ftppic");
//            File[] fs = files.listFiles();
//            for (File file : fs) {
//                ftpClientUtils.upload(file, "/violate/cross1/"+file.getName());
//                
//            }
//        } catch (IOException e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        }

        try {
            // 打开连接
            ftpClientUtils.open();
            FTPFile[] exists = ftpClientUtils.ftpClient.listFiles("/cross/陕A99V0u61.jpg");
            for (FTPFile ftpFile : exists) {
                System.out.println(ftpFile.getName());
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}

工具类用法

FtpClientUtils ftpClientUtils = new FtpClientUtils(ftpInfo.getFtpip(), ftpInfo.getFtpuser(), ftpInfo.getFtppassword(), Integer.parseInt(ftpInfo.getFtpport()));
            File f=new File(filePath);
            try {
                /*fileName=new String(fileName.getBytes("GBK"),"iso-8859-1");*/
                UploadStatus s=    ftpClientUtils.upload(f, fileName);
                logger.info("上传成功......");
                if(s==UploadStatus.UPLOAD_NEW_FILE_SUCCESS){
                    return true;
                }else{
                    return false;
                }
            } catch (Exception e2) {
                // TODO Auto-generated catch block
                e2.printStackTrace();
                logger.error(e2);
                return false;
            }finally{
                ftpClientUtils.close();
            }

代码介绍:首先通过构造方法传入FTP服务器的IP,用户名密码,端口号,初始化FTP工具类得到对象ftpClientUtils,然后通过执行upload方法得到上传结果,上传结果返回的是一个枚举类型;代码见下面:

// 枚举上传状态
    public enum UploadStatus {
        CREATE_DIRECTORY_FAIL, // 远程服务器相应目录创建失败
        CREATE_DIRECTORY_SUCCESS, // 远程服务器创建目录成功
        UPLOAD_NEW_FILE_SUCCESS, // 上传新文件成功
        UPLOAD_NEW_FILE_FAILED, // 上传新文件失败
        FILE_EXITS, // 文件已经存在
        REMOTE_BIGGER_LOCAL, // 远程文件大于本地文件
        UPLOAD_FROM_BREAK_SUCCESS, // 断点续传成功
        UPLOAD_FROM_BREAK_FAILED, // 断点续传失败
        DELETE_REMOTE_FAILD; // 删除远程文件失败
    }

好了,基于java FTPClient实现的FTP上传工具类就介绍到这里,希望对大家也有帮助。

酷码派 [KuMaPai.COM] - 陕ICP备案证 18010024号-2