Java FTP客户端库回顾
了解可用的库是和进行互相比较
摘要
本文解释了如何利用库用Java语言编写FTP客户端代码。它比较了FTP库的一个完全列表,演示了每个库的优点和缺点,并且帮助决策者为他们的需要选择适当的库。另外,本文阐述了Fa?ade模式如何在取代一个库时改变管理。最后,作者Jean-Pierre Norguet讨论并解决了由于缺乏权威性的说明书引起的一些问题。
让我们假设一个情景:我们要编写一个纯Java应用程序,该程序必须从运行FTP服务器的远程计算机上下载文件。我们也通过远程文件信息,像名字、日期、或者尺寸,来过滤下载。
自己来写一个FTP协议处理,尽管是有可能,并且可能很有趣。但是这样做也有可能有困难、花费长时间、并且有潜在的风险。既然我们不肯花费时间、精力、或者金钱自己来写一个处理器,那我们推荐使用一个可重用的现有的软件组件。万维网上有并且大量的库可供使用。有了一个FTP客户端库,下载一个文件用Java语言编写就像下面一样简单:
FTPClient ftpClient = new FTPClient();
ftpClient.connect("ftp.foo.com", "user01", "pass1234");
ftpClient.download("C:\\Temp\\", "README.txt");
// Eventually other operations here ...
ftpClient.disconnect();
寻找一个适合我们需要的高质量的Java FTP客户端库并不像他看起来那么简单;它可能相当困难。要找到一个Java FTP客户端库需要花一些时间。接着,在我们找到所有的已存在的库之后,我们选哪个?每个库适合不同的需要。库在质量上是不等的,并且它们的设计有本质的区别。每个提供一套不同的属性和使用不同类型的行话来描述他们。
因此,计算和比较FTP客户端库证明是困难而且令人迷惑的。重复使用已存在的组件是一个值得推荐的过程,但在这个例子中,启动它也是令人沮丧的。并且这有点羞愧:在选好的一个好的FTP库之后,剩下的工作就是例程了。
本文旨在使选择过程简短、容易、并且有价值。我首先列出了所有的FTP客户端库。接着,我定义和描述了库应该用某种方式找到的相关标准的一个表格。最后,我列出了一个总浏览的矩阵,该矩阵给出了库间相互比较的过程的快速浏览。所有的信息提供了我们作出一个迅速、可靠、和长期的决定所需的每件事。
使用JDK(Java 开发工具集)的FTP支持
用于FTP的访问规范是用于注释的请求:959(RFC959)。Sun Microsystems提供了JDK的一个RFC959执行。但是它是内部的、非文档化的、并且不提供任何资源。当RFC959在尚未公开时,它实际上是执行RFC1738、URL规范的一个公共界面的后终端。如图1。
图1. 使用JDK的FTP支持。
RFC1738的一个执行过程在JDK中作为标准给出。它为基本的FTP传送做一个可推理的工作。它是公共的、文档化的、并且提供源代码。要使用它,我们可编写下面语句:
URL url = new URL("ftp://user01:pass1234@ftp.foo.com/README.txt;type=i");
URLConnection urlc = url.openConnection();
InputStream is = urlc.getInputStream(); // To download
OutputStream os = urlc.getOutputStream(); // To upload
使用JDK的FTP客户端严格的遵守标准推荐,但它有以下几个说明:
它从根本上区别于第三方的FTP客户端库;这些执行RFC959而不是RFC1738
RFC959用大多数的桌面FTP客户端工具执行。许多Java程序员使用这些工具连接到FTP服务器上。作为一个尝试,这些工具及有可能优先于类似的RFC959库。
URL 和URLConnection类只开放用于通讯的流。Sun库不为构造原始的FTP服务器响应成为像String、 File、 RemoteFile、 或者 Calendar之类的更合用的Java对象而提供直接支持。所以我们不得不编写更多的代码,只是为了把数据写入一个文件中或者开始一个目录列表。
正像RFC1738的3.2部分解释的一样,"最优化",FTP URL在每个操作后要求关闭(控制)连接。这对于传送许多小文件是一种浪费、并且毫无效率。而且,作了特别限制FTP服务器可能把会这样一个通讯开销认为一个是恶毒的网络攻击或者滥用而拒绝提供进一步的服务。
最后,它缺乏几个有用的属性。
由于以上所有或者某种原因,可优先使用一个第三方的库。下面部分列出了可供选择的第三方的库。
库比较
下表中列出了我要比较的库。他们都遵守访问FTP规范。接下来,我提供了供应商名字和库名(用斜体字)。Resources包括到每个产品网站的链接。为了快速使用这些库,我也提到了其主要的FTP客户端类。
1. JScape, iNet Factory: com.jscape.inet.ftp.Ftp
2. /n 软件, IP*Works: ipworks.Ftp
3. 企业分布式技术, Java FTP Client Library: om.enterprisedt.net.ftp.FTPClient
4. IBM alphaWorks, FTP Bean Suite: com.ibm.network.ftp.protocol.FTPProtocol
5. SourceForge, JFtp: net.sf.jftp.net.FtpConnection
6. The Jakarta Project, Jakarta Commons/Net: org.apache.commons.net.ftp.FTPClient
7. JavaShop JNetBeans: jshop.jnet.FTPClient
8. Sun, JDK: sun.net.ftp.FtpClient
9. Florent Cueto, JavaFTP API: com.cqs.ftp.FTP
10. Bea Petrovicova, jFTP: cz.dhl.ftp.Ftp
11. The Globus Project, Java CoG Kit: org.globus.io.ftp.FTPClient
注意:
在写这篇文章时,IBM正在评测在它的站点上提供alphaWorks FTP Bean Suite的适合性。现在,下载对所有用户关闭。
Jakarta Commons/Net是代替了Savarese NetComponents。Savarese NetComponents将不会再被发展。
JavaShop JnetBeans好像已经废弃不用了。在写这篇文章时,站点已经离线一个多月了,并且我没有收到对我支持请求的任何响应。
标准
至此,我已经介绍并列出了可用的库。现在,我列出针对于要求评估的每个库的相关标准。我对于每一个标准量化了可能值,和在最后比较矩阵中使用的缩写(粗体)放在一起。
产品支持
库通过产品文档、编译的Java文档、样品代码和一个包括注释和解释的应用程序范例给用户提供支持。附加的支持可通过论坛、邮件列表、一个联系的email地址、或者一个在线故障追踪系统提供给用户。/n软件提供附加的支持是要另外收费的。
一个支持管理员的目的是快速支持的一个重要因素。支持管理员可以是:
一个志愿者(I)
一个志愿小组(G)
一个付费的专家团体提供支持(P)
许可证
对于商业项目来说,产品许可证是从一开始就要考虑的一件重要的事。一些库可以自由的重用在商业产品中,但另一些就不能。GPL(GNU通用公共许可证)是一个强大的、有条件的许可证,然而Apache Software许可证只要求在重用的产品中说明一下。
商业许可证限制了利用库开发工作站编程的数目,但是不限制库本身的分布。
对于非商业的项目来说,许可证更像一个哲学问题,一个免费产品是令人感激的。
许可证可以是:
商业(C)
GPL(G)
免费(F);但是,得检测一个免费许可证的限制条件。
一些库供应商要求提供备选的、限制较少的许可证。
提供的源代码
一个封闭源代码的,黑-盒子的软件库可能是使人生气的。由于下面的原因,提供源代码会让他更方便使用:
当应用程序代码执行出现故障时,进入库代码资源可帮助你理解库的行为。
源代码包含有用的注释
源代码可迅速的调整,以便适应新的需要
示范的源代码可以检测
寿命
库从他们首次公开发行时已经被测试、修复故障和支持。由于版本数在库中变化。我以最早的公开发行年的该标准为基准。
目录列表支持
检索来自服务器的远程文件信息(名称、尺寸、日期)在多数应用程序中是重要的。FTP协议提供NLST指令检索到文件名;NLST命名被精确的设计以便程序调用。LIST命令提供更多的文件信息;像RFC959注释的那样:"由于文件上的信息可能从系统到系统的广泛的不一致,该信息难以在一个程序中自动使用,但是对于人类用户来说相当有用。"没有其他标准方法检索文件信息;因此,客户端库试图调用LIST响应。但是,这可不是一件容易的事情:既然没有权威性的推荐可用于LIST相应格式,FTP服务器采用了不同的格式:
Unix类型:drwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog
备选的Unix类型:drwxr-xr-x 1 user01 ftp 512 Jan 29 1997 prog
备选的Unix类型:drwxr-xr-x 1 1 1 512 Jan 29 23:32 prog
使用Unix类型的符号链接:lrwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog -> prog2000
Weird Unix类型(用户和小组之间无间距):drwxr-xr-x 1 usernameftp 512 Jan 29 23:32 prog
MS-DOS类型:01-29-97 11:32PM <DIR> prog
Macintosh类型:drwxr-xr-x folder 0 Jan 29 23:32 prog
OS/2类型:0 DIR 01-29-97 23:32 PROG
Unix类型,其次是MS-DOS类型,是使用最广的格式。
Java FTP客户端库试图理解和自动检测尽可能多的格式。另外,他们提供用于处理不可预知的格式应答的不同备选项:
一个附加的方法,返回作为一个字符串的原始FTP响应(S)
一个附加的方法,返回原始字符串集,每行/文件一个字符串(C)
一个支持可插剖析器的框架(P)
大多数的库捕捉LIST响应并将原始文件信息组织成Java 对象,例如:有了JScape iNet库,下列代码检索并且调用收到的文件信息到一个目录列表中:
java.util.Enumeration files = ftpClient.getDirListing();
while (files.hasMoreElements()) {
FtpFile ftpFile = (FtpFile) files.nextElement();
System.out.println(ftpFile.getFilename());
System.out.println(ftpFile.getFilesize());
// etc. other helpful methods are detailed in Javadoc
}
"遗留问题解答"部分将进一步讨论目录列表。
时间标签检索
在许多情况下,我们对一个远程文件的最近的修改的时间标签感兴趣。不幸的是,没有RFC介绍检索该信息的一个标准FTP命令。下面有两个实用的方法:
1. 通过捕捉服务器回答从LIST响应中检索该信息。但是,正像你在前面部分学到的一样,LIST响应在FTP服务器中各不相同,并且时间标签信息有时还不完整。使用Unix格式,当远程文件存在一年以上时会存在不精确性:只有日期和年份,没有小时或者分钟部分。
2. 使用非标准的MDTM命令。该命令专门检索一个远程文件的最新修改的时间标签。可惜,不是所有的FTP服务器都执行这个命令。
MDTM命令的一个复杂的备选项支持就是发送一条原始的MDTM命令并且捕捉命令。多数库提供发送一条原始的FTP命令的一个方法,像:
String timeStampString = ftpClient.command("MDTM README.txt");
另一个可能的方面就是FTP服务启用GMT(格林威治标准时间)返回时间信息。如果已知服务器时区与FTP通讯分离的话,那么java.util.TimeZone.getOffset()函数能帮助调整时区之间的差别。进一步了解该函数的信息请查看JDK文档。
"遗留问题解答"部分进一步讨论文件时间标签检索。
防火墙
典型的,防火墙设置在一个私人的企业网络和公共网络,如因特网,之间。它可管理从私人网络到公共网络的访问,但是从公共网络到私人网络的访问被否决。
Socks是一个作为因特网防火墙网关使用而开发的公共的、合用的协议。JDK支持Socks 4 和 Socks 5代理。他们由库中的某些部分控制。作为备选项,JVM命令行可设置Socks 代理参数:java -DsocksProxyPort=1080 -DsocksProxyHost=socks.foo.com -Djava.net.socks.username=user01 -Djava.net.socks.password=pass1234 ...
另一个通用的Socks 代理支持备选项是"Socks 化"客户端设备在下面的TCP/IP层。
JDK也支持HTTP通道,这些广泛使用的代理不允许FTP上传。/n软件的IP*Works允许你设置HTTP通道参数。
多数库既支持活跃的、也支持被动的连接:当客户端在接受引入的连接到更高的端口的防火墙后面时,被动连接有用。RFC1579更详细的讨论了这个友好的防火墙功能性。一些产品的文件把活跃和被动的链接分别看作PORT 和 PASV命令。
并行传送
在一个桌面应用程序中,当在主单线程中的传送启动时,一切事情都冻结了。一些库自动的服务于在单独的线上并行传送的事件循环,因此我们不必创建和管理我们自己的线程。
JavaBean说明书支持
一些库实现JavaBean说明书。JavaBean默认允许可视的编程,它在主要的Java IDE中特征化。
/n软件的IP*Works、JavaBean设计是基于事件的(例如:ipworks.Ftp.listDirectory()函数)。尽管它保持同步并且相当安全,一些程序员还是发现它在服务器端的应用程序显得多余或者笨拙。
进程监督
一些库执行进程监督。进程监督支持使得执行追踪任何FTP传送的进程的事件监听器更为容易。 当开发一个友好的用户界面时,这个特征会有用。
传输类型
RFC959 3.1.1部分定义了几种传输类型,其中两个是常见的ASCII nonprint (默认) 和image (也称 binary)。有些库可根据文件扩展用自动模式设置,这样一种方法在现代信息系统很少有用,另一种传输类型已经废弃了并且不被任何一种Java支持。
其他标准说明
所有的库至少要在JDK 1.2.x或者更新的版本上运行;多数应该在JDK 1.1.x上运行,甚至是JDK 1.0.x。
所有库是纯Java语言的。
比较矩阵列出了其他明显的标准。
Java FTP客户端库:比较矩阵
现在出现的是最后的比较矩阵。它在左边列的是标准,顶上列的是库,它列出了与左边标准对应的在上面的库。在单元中,Y表示"是";其他缩写在上面的标准列表(用粗体字标出的字母)和表格的密码中解释过。
当选择一个库时,我有几条建议:
服务器端应用程序,我推荐Jakarta Commons/Net 库
JScape's iNetFactory我发现是最容易使用的库
/n软件的IP*Works是广泛使用的包含FTP加密支持的产品中的一部分。
Java CoG Kit也执行GridFTP。GridFTP是一个有趣的新一代文件传送系统。
在写本文时,我建议不使用当前条件下的IBM的 alphaWorks FTP Bean Suite和JavaShop的 JnetBeans。
其它库绝对得体并且适合你的需要;请参考矩阵。
见:http://www.javaworld.com/javaworld/jw-04-2003/ftp/jw-0404-ftptable.html
变动管理
在我们项目中的某些点上,特别是在项目快结束彻底测试时,很有可能我们想修改我们的库。这样一种变化影响了所有我们的调用代码:我们的类将不再编译,一些应用部分必须重新编码,以便适合不同的方法名称和新库的不同设计。
既然管理这样一个变动证明是很烦的,特别在项目快结束时,时间成为一个关键资源时我们应该将改动限制在一个个别的类中。典型的,我们应用Fa?ade模式,当FTP库当作后终端时,见图2。
图2 Fa?ade 模式 应用到一个FTP库中
应用Fa?ade模式到FTP库上的一个好的影响是我们可以添加值到库本身上。例如,我们可以编写一个Fa?ade程序,用它下载整个远程目录到一个当地压缩文件或者一个程序上。该程序执行库中缺乏的任何基本属性。
最后,有相同签名的两个库运行时间不一定相同。因此,从一个库切换到另一个库上,也能影响我们应用程序的运行时间。这样一种影响是令人难过和不舒服的。因为发现运行时间的区别要难得多,尽管详细的测试情况可能有所帮助。
在上述标准的阐述中,我简洁的描述了几种不能解决的问题。在这个部分,我要进一步讨论并解决它们;我建议一个长期的解决方案和一个短期的解决方法。
目录列表
缺乏对LIST响应的任何权威性说明书导致了许多不同的FTP服务器的出现。这个缺乏对与FTP客户端程序员来说是最大的问题,并且它仍然是一个开放的难题。
由于问题的根本在于协议的定义,我推荐相关的权威性机构,因特网工程任务组织(IETF),用一个新的参考文档说明书(一个RFC)定义了LIST响应结构。
过程是漫长的,同时,最灵活的解决方案是使用一个提供了可插入的格式解释器的框架的库。
文件时间标签检索
就像我刚才讨论的一样,没有方法通过FTP检索一个远程文件的最新的修改时间标签。我为传送从服务器到客户端的时间标签建议两个长期的解决方案:
1. 在LIST响应中包括精确而且完整的时间标签
2. 标准化MDTM命令和响应
对于两种方案来说,都要在通讯过程中考虑服务器的时区问题。
再次,因为问题的根本在于协议定义,我推荐IETF定义一种或者上述两种方案作为一个权威性的规范使用。
同时,最常用的短期解决方法就是使用对LIST和MDTM响应捕捉都支持的库,并且开发这两种属性的联合体。
变动管理
在上述相关部分,我推荐了Fa?ade模式在库更替过程中减少变动影响。就像我说到的,模式并不是一个万能药,因为库中行为的缺乏仍能在运行时间内影响我们整个的应用程序,它是难以控制的。
因为这个方面是一个纯粹的编码问题,我建议Sun公司出版一个标准的设计良好的API,定义精确的程序和行为。任何人包括Sun公司在内,都能执行这个程序。程序员能使用界面程序并用它们指定的执行过程支持他们。任何从一个库到另一个库的切换会对应用程序的剩余部分产生最小的冲击。Java Mail和JDBC(Java数据库连接)API是示范性的引用单元。
Java FTP API标准化项目旨在组织一个用户、开发商、和供应商的联盟,把改进请求作为一个Java规范请求引入Java社区进程中。你的支持当然对该项目有用,它的主页可在Resources中找到。
为你的需要找到最好的库
在本文中,我阐述了如何用Java编写FTP客户端代码并且列举了JDK和第三方的库的FTP客户端支持。我也展示了在计算不同的库的过程中要考虑的重要标准和库之间比较的标准。我希望决策者在面对Java FTP客户端库的选择时在本文中找到有用的提示,从而作出最好的决定。
最后,我说明了对所有FTP库普遍存在的不同的问题,并且建议了短期的解决方法以及可能被权威性机构像IETF和Sun公司采用的长期解决方案。我希望这些先导和行为有助于铸造Java FTP客户端库的未来。
关于作者
Jean-Pierre Norguet, Libre de Bruxelles大学学士学位,巴黎Libre de Bruxelles苏格拉底欧洲硕士,在IBM 任务鉴定电子商务应用程序的Java开发小组担任过三年全职的领导和教练。他擅长于整个应用程序生活周期的开发。现在是比利时布鲁塞尔调查组成员,编写关于因特网观众分析的一篇博士学位论文。他的爱好包括艺术绘画欣赏、观看法国戏院表演和享受舒适的按摩。