开发者社区> 技术小阿哥> 正文

基于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 == nullreturn 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 == nullreturn 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 
-1 

Process finished with exit code 0
 
可见,打印的结果与实际情况相符。


本文转自 leizhimin 51CTO博客,原文链接:http://blog.51cto.com/lavasoft/236934,如需转载请自行联系原作者

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
18052 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
23588 0
[Linux 性能检测工具]DF
DF NAME: df 报告了文件系统的使用 语法: df [OPTION]... [FILE]... 描述: Df显示了以文件名为从参数查看所在文件系统的可用空间。如果没有指定文件那么会显示所有的文件系统,磁盘空间默认是1k block,除非POSIXLY_CORRECT被设置,这样就会使用512-byte块。
593 0
选择一个运行Derby工具和启动辅助程序的方法
有多种方法可以运行Derby 工具和启动辅助程序。 可以运行工具和启动实用程序的方法基于你Derby环境变量的设置。 1. 选择你期望使用的方法: ------------------------------------------------------------------------------------------------ 方法: 使用Derby提供的命令行方式运行工具。
673 0
Remoting客户端代理类工具SoapSuds
SoapSuds工具的作用在此就不多说了。简单地说,就是产生程序集的元数据,而这主要使用在Remoting架构中。 在Remoting中,为了达到客户端和服务端对远程对象元数据的分离,使用SoapSuds工具产生远程对象的元数据,这样在客户端就不用引用远程对象的程序集了。
599 0
一个内存增长问题的分析和处理(二)——valgrind工具的用法
valgrind是linux下对C++和C程序进行内存泄露检测的工具,除了内存检测,valgrind还提供了很多其他的功能,这里主要介绍下valgrind的内存检测的功能。   首先是文件的下载,valgrind的官方网址是http://valgrind.org/,最新版本的valgrind是3.9,下载地址如下:http://valgrind.org/downloads/。
808 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
17564 0
【我的Android进阶之旅】推荐一款视频转换GIF图片格式的转换工具(Video to GIF)
一、背景 最近想把一些Android Demo的运行效果图获取下来,但是一直使用真机进行调试,在电脑上不好截取一段gif动画。而之前使用模拟器的时候可以使用 GifCam 工具进行屏幕动画截取。
1787 0
13692
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
OceanBase 入门到实战教程
立即下载
阿里云图数据库GDB,加速开启“图智”未来.ppt
立即下载
实时数仓Hologres技术实战一本通2.0版(下)
立即下载