zoukankan      html  css  js  c++  java
  • 基于ftp4j的FTP客户端工具

    基于ftp4j的FTP客户端工具

    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能。可以将ftp4j嵌到你的Java应用中,来传输文件(包括上传和下载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括:通过TCP/IP直接连接,通过FTP代理、HTTP代理、SOCKS4/4a代理和SOCKS5代理连接,通过SSL安全连接。

    ftp4j这是一个基本类库,用起来有些不爽,首先是受检查异常太多太多,这是合理的,把异常留给使用者灵活处理,其次是提供的客户单API太基础,还不够强悍。下面是我针对实际中最常用的功能所作的一个工具类。

    在对待异常的方式上,将检查异常全转换为运行时异常,并对一些潜在操作的错误进行检查,提供了原API中没有的一些功能,批量下载、任务侦听器、检查FTP上文件或目录是否存在以及类型。
     
    下面是实现代码:
    package lavasoft.common.ftp;

    import it.sauronsoftware.ftp4j.FTPClient;
    import it.sauronsoftware.ftp4j.FTPFile;
    import lavasoft.common.PathToolkit;

    import java.io.File;
    import java.util.List;

    /**
    * TTP客户端工具
    *
    * @author leizhimin 2009-11-30 10:20:17
    */

    public final class FTPToolkit {

            private FTPToolkit() {
            }

            /**
             * 创建FTP连接
             *
             * @param host         主机名或IP
             * @param port         ftp端口
             * @param username ftp用户名
             * @param password ftp密码
             * @return 一个客户端
             */

            public static FTPClient makeFtpConnection(String host, int port, String username, String password) {
                    FTPClient client = new FTPClient();
                    try {
                            client.connect(host, port);
                            client.login(username, password);
                    } catch (Exception e) {
                            throw new FTPRuntimeException(e);
                    }
                    return client;
            }

            /**
             * FTP下载文件到本地一个文件夹,如果本地文件夹不存在,则创建必要的目录结构
             *
             * @param client                    FTP客户端
             * @param remoteFileName    FTP文件
             * @param localFolderPath 存的本地目录
             */

            public static void download(FTPClient client, String remoteFileName, String localFolderPath) {
                    int x = isExist(client, remoteFileName);
                    MyFtpListener listener = MyFtpListener.instance(FTPOptType.UP);
                    File localFolder = new File(localFolderPath);
                    if (localFolder.isFile()) {
                            throw new FTPRuntimeException("所要的下载保存的地方是一个文件,无法保存!");
                    } else {
                            if (!localFolder.exists())
                                    localFolder.mkdirs();
                    }
                    if (x == FTPFile.TYPE_FILE) {
                            String localfilepath = PathToolkit.formatPath4File(localFolderPath + File.separator + new File(remoteFileName).getName());
                            try {
                                    if (listener != null)
                                            client.download(remoteFileName, new File(localfilepath), listener);
                                    else
                                            client.download(remoteFileName, new File(localfilepath));
                            } catch (Exception e) {
                                    throw new FTPRuntimeException(e);
                            }
                    } else {
                            throw new FTPRuntimeException("所要下载的文件" + remoteFileName + "不存在!");
                    }
            }

            /**
             * FTP上传本地文件到FTP的一个目录下
             *
             * @param client                     FTP客户端
             * @param localfile                本地文件
             * @param remoteFolderPath FTP上传目录
             */

            public static void upload(FTPClient client, File localfile, String remoteFolderPath) {
                    remoteFolderPath = PathToolkit.formatPath4FTP(remoteFolderPath);
                    MyFtpListener listener = MyFtpListener.instance(FTPOptType.UP);
                    try {
                            client.changeDirectory(remoteFolderPath);
                            if (!localfile.exists()) throw new FTPRuntimeException("所要上传的FTP文件" + localfile.getPath() + "不存在!");
                            if (!localfile.isFile()) throw new FTPRuntimeException("所要上传的FTP文件" + localfile.getPath() + "是一个文件夹!");
                            if (listener != null)
                                    client.upload(localfile, listener);
                            else
                                    client.upload(localfile);
                            client.changeDirectory("/");
                    } catch (Exception e) {
                            throw new FTPRuntimeException(e);
                    }
            }

            /**
             * FTP上传本地文件到FTP的一个目录下
             *
             * @param client                     FTP客户端
             * @param localfilepath        本地文件路径
             * @param remoteFolderPath FTP上传目录
             */

            public static void upload(FTPClient client, String localfilepath, String remoteFolderPath) {
                    File localfile = new File(localfilepath);
                    upload(client, localfile, remoteFolderPath);
            }

            /**
             * 批量上传本地文件到FTP指定目录上
             *
             * @param client                     FTP客户端
             * @param localFilePaths     本地文件路径列表
             * @param remoteFolderPath FTP上传目录
             */

            public static void uploadListPath(FTPClient client, List<String> localFilePaths, String remoteFolderPath) {
                    remoteFolderPath = PathToolkit.formatPath4FTP(remoteFolderPath);
                    try {
                            client.changeDirectory(remoteFolderPath);
                            MyFtpListener listener = MyFtpListener.instance(FTPOptType.UP);
                            for (String path : localFilePaths) {
                                    File file = new File(path);
                                    if (!file.exists()) throw new FTPRuntimeException("所要上传的FTP文件" + path + "不存在!");
                                    if (!file.isFile()) throw new FTPRuntimeException("所要上传的FTP文件" + path + "是一个文件夹!");
                                    if (listener != null)
                                            client.upload(file, listener);
                                    else
                                            client.upload(file);
                            }
                            client.changeDirectory("/");
                    } catch (Exception e) {
                            throw new FTPRuntimeException(e);
                    }
            }

            /**
             * 批量上传本地文件到FTP指定目录上
             *
             * @param client                     FTP客户端
             * @param localFiles             本地文件列表
             * @param remoteFolderPath FTP上传目录
             */

            public static void uploadListFile(FTPClient client, List<File> localFiles, String remoteFolderPath) {
                    try {
                            client.changeDirectory(remoteFolderPath);
                            remoteFolderPath = PathToolkit.formatPath4FTP(remoteFolderPath);
                            MyFtpListener listener = MyFtpListener.instance(FTPOptType.UP);
                            for (File file : localFiles) {
                                    if (!file.exists()) throw new FTPRuntimeException("所要上传的FTP文件" + file.getPath() + "不存在!");
                                    if (!file.isFile()) throw new FTPRuntimeException("所要上传的FTP文件" + file.getPath() + "是一个文件夹!");
                                    if (listener != null)
                                            client.upload(file, listener);
                                    else
                                            client.upload(file);
                            }
                            client.changeDirectory("/");
                    } catch (Exception e) {
                            throw new FTPRuntimeException(e);
                    }
            }


            /**
             * 判断一个FTP路径是否存在,如果存在返回类型(FTPFile.TYPE_DIRECTORY=1、FTPFile.TYPE_FILE=0、FTPFile.TYPE_LINK=2)
             * 如果文件不存在,则返回一个-1
             *
             * @param client         FTP客户端
             * @param remotePath FTP文件或文件夹路径
             * @return 存在时候返回类型值(文件0,文件夹1,连接2),不存在则返回-1
             */

            public static int isExist(FTPClient client, String remotePath) {
                    remotePath = PathToolkit.formatPath4FTP(remotePath);
                    int x = -1;
                    FTPFile[] list = null;
                    try {
                            list = client.list(remotePath);
                    } catch (Exception e) {
                            return -1;
                    }
                    if (list.length > 1) return FTPFile.TYPE_DIRECTORY;
                    else if (list.length == 1) {
                            FTPFile f = list[0];
                            if (f.getType() == FTPFile.TYPE_DIRECTORY) return FTPFile.TYPE_DIRECTORY;
                            //假设推理判断
                            String _path = remotePath + "/" + f.getName();
                            try {
                                    int y = client.list(_path).length;
                                    if (y == 1) return FTPFile.TYPE_DIRECTORY;
                                    else return FTPFile.TYPE_FILE;
                            } catch (Exception e) {
                                    return FTPFile.TYPE_FILE;
                            }
                    } else {
                            try {
                                    client.changeDirectory(remotePath);
                                    return FTPFile.TYPE_DIRECTORY;
                            } catch (Exception e) {
                                    return -1;
                            }
                    }
            }

            /**
             * 关闭FTP连接,关闭时候像服务器发送一条关闭命令
             *
             * @param client FTP客户端
             * @return 关闭成功,或者链接已断开,或者链接为null时候返回true,通过两次关闭都失败时候返回false
             */


            public static boolean closeConnection(FTPClient client) {
                    if (client == null) return true;
                    if (client.isConnected()) {
                            try {
                                    client.disconnect(true);
                                    return true;
                            } catch (Exception e) {
                                    try {
                                            client.disconnect(false);
                                    } catch (Exception e1) {
                                            e1.printStackTrace();
                                            return false;
                                    }
                            }
                    }
                    return true;
            }
    }
     
    package lavasoft.common;

    import java.io.File;

    /**
    * 路径处理工具,操作系统自适应
    *
    * @author leizhimin 2009-11-30 16:01:34
    */

    public final class PathToolkit {
            private PathToolkit() {
            }

            /**
             * 格式化文件路径,将其中不规范的分隔转换为标准的分隔符,并且去掉末尾的文件路径分隔符。
             * 本方法操作系统自适应
             *
             * @param path 文件路径
             * @return 格式化后的文件路径
             */

            public static String formatPath4File(String path) {
                    String reg0 = "////+";
                    String reg = "////+|/+";
                    String temp = path.trim().replaceAll(reg0, "/");
                    temp = temp.replaceAll(reg, "/");
                    if (temp.length() > 1 && temp.endsWith("/")) {
                            temp = temp.substring(0, temp.length() - 1);
                    }
                    temp = temp.replace('/', File.separatorChar);
                    return temp;
            }

            /**
             * 格式化文件路径,将其中不规范的分隔转换为标准的分隔符
             * 并且去掉末尾的"/"符号(适用于FTP远程文件路径或者Web资源的相对路径)。
             *
             * @param path 文件路径
             * @return 格式化后的文件路径
             */

            public static String formatPath4FTP(String path) {
                    String reg0 = "////+";
                    String reg = "////+|/+";
                    String temp = path.trim().replaceAll(reg0, "/");
                    temp = temp.replaceAll(reg, "/");
                    if (temp.length() > 1 && temp.endsWith("/")) {
                            temp = temp.substring(0, temp.length() - 1);
                    }
                    return temp;
            }

            /**
             * 获取FTP路径的父路径,但不对路径有效性做检查
             *
             * @param path FTP路径
             * @return 父路径,如果没有父路径,则返回null
             */

            public static String genParentPath4FTP(String path) {
                    String pp = new File(path).getParent();
                    if (pp == null) return null;
                    else return formatPath4FTP(pp);
            }
    }
     
    package lavasoft.common.ftp;

    /**
    * FTP操作类型
    *
    * @author leizhimin 2009-11-30 11:16:59
    */

    public enum FTPOptType {
            UP("上传"),
            DOWN("下载"),
            LIST("浏览"),
            DELFILE("删除文件"),
            DELFOD("删除文件夹"),
            RENAME("上传");

            private String optname;

            FTPOptType(String optname) {
                    this.optname = optname;
            }

            public String getOptname() {
                    return optname;
            }
    }
     
    package lavasoft.common.ftp;

    import it.sauronsoftware.ftp4j.FTPDataTransferListener;

    /**
    * FTP监听器,做了简单实现,可以使用commons logger替换System.out.println
    *
    * @author leizhimin 2009-11-30 11:05:33
    */

    public class MyFtpListener implements FTPDataTransferListener {
            private FTPOptType optType;

            public static MyFtpListener instance(FTPOptType optType) {
                    return new MyFtpListener(optType);
            }

            private MyFtpListener(FTPOptType optType) {
                    this.optType = optType;
            }

            public void started() {
                    System.out.println(optType.getOptname() + ":FTP启动喽。。。。。。");
            }

            public void transferred(int length) {
                    System.out.println(optType.getOptname() + ":FTP传输喽。。。。。。");

            }

            public void completed() {
                    System.out.println(optType.getOptname() + ":FTP完成喽。。。。。。");
            }

            public void aborted() {
                    System.out.println(optType.getOptname() + ":FTP中止喽。。。。。。");
            }

            public void failed() {
                    System.out.println(optType.getOptname() + ":FTP挂掉喽。。。。。。");
            }
    }
     
    package lavasoft.common.ftp;

    /**
    * FTP异常
    *
    * @author leizhimin 2009-11-30 10:28:03
    */

    public class FTPRuntimeException extends RuntimeException {
            public FTPRuntimeException() {
                    super();
            }

            public FTPRuntimeException(String message) {
                    super(message);
            }

            public FTPRuntimeException(String message, Throwable cause) {
                    super(message, cause);
            }

            public FTPRuntimeException(Throwable cause) {
                    super(cause);
            }
    }
     
    package lavasoft;

    import it.sauronsoftware.ftp4j.FTPClient;
    import lavasoft.common.ftp.FTPToolkit;

    /**
    * 简单测试下
    *
    * @author leizhimin 2009-11-30 12:25:42
    */

    public class Test {
            public static void main(String args[]) throws Exception {
                    String ftpip = "192.168.104.113";
                    int ftpport = 21;
                    String ftpuser = "vcomkp.ftpadmin";
                    String ftppswd = "ftp";

                    FTPClient client = FTPToolkit.makeFtpConnection(ftpip, ftpport, ftpuser, ftppswd);
                    FTPToolkit.upload(client, "C://Dynamicclrr4.zip", "/aaa/bbb/ccc");
                    FTPToolkit.download(client, "/Dynamicclrr4.zip", "D://");
                    FTPToolkit.closeConnection(client);
            }
    }
     
    上传:FTP启动喽。。。。。。
    上传:FTP传输喽。。。。。。
    上传:FTP传输喽。。。。。。
    上传:FTP完成喽。。。。。。
    上传:FTP启动喽。。。。。。
    上传:FTP传输喽。。。。。。
    上传:FTP传输喽。。。。。。
    上传:FTP完成喽。。。。。。

    Process finished with exit code 0
     
    本程序在RedHat AS 5上使用vsftpd测试通过,一般来说windows下测试通过的ftp工具,一般在Linux下通不过,因为Windows没有太多权限控制。而Linux控制非常严格,常常因为没有权限而导致操作失败,这时候,要对Linux的FTP用户给读写的权限才能正确执行以上代码。

    另外说明一点,在判断ftp服务器上一个文件是否存在的isExist方法,具有一定一个局限性,体现在两方面:一是对特定组件版本的依赖性,不同版本list等方法实现不同,对错误路径的处理也不同。二是,不同的ftp服务器对发送list命令反馈的结果不尽相同。
     
    这也是为什么很多ftp组件工具不去实现isExist的方法。对使用本方法测试有异常不符合事实的情况下,需要根据特定的环境测试重新实现isExist方法即可。
     
    这里我给出了一个测试:
    我用的vsftp目录结构如下
    /aaa
    /aaa/bbb/ccc
    /aaa/bbb/ccc/Dynamicclrr4.zip
     
    调用方法测试:
                    System.out.println(FTPToolkit.isExist(client, "/aaa/bbb/ccc"));                                    //目录
                    System.out.println(FTPToolkit.isExist(client, "/aaa/bbb/ccc/Dynamicclrr4.zip")); //文件
                    System.out.println(FTPToolkit.isExist(client, "/aaa/bbb/ccc/xxxxxx.zip"));             //不存在的文件
                    System.out.println(FTPToolkit.isExist(client, "/aaa/bbb/pppppdd"));                            //不存在的目录
     
    1
    0
    -1
    -1

    Process finished with exit code 0
     
    可见,打印的结果与实际情况相符。
  • 相关阅读:
    洛谷P5661 公交换乘(二分)
    洛谷P4047 [JSOI2010]部落划分(最小生成树)
    洛谷P2872 [USACO07DEC]Building Roads S(最小生成树)
    卸载重装VirtualBox回滚报错
    POJ1151 Atlantis(扫描线+线段树+离散化)
    QT入门-信号槽拓展
    Vue模板语法与常用指令总结
    Vue 生命周期
    querySelector和getElementById方法的区别
    ES6 Class(类)的继承与常用方法
  • 原文地址:https://www.cnblogs.com/cuker919/p/4878616.html
Copyright © 2011-2022 走看看