commons-net-1.4.1.jar包中ftp应用的几点问题
一、异常:
从http://commons.apache.com/网站下载了commons-net-1.4.1包后添加到自己的工程中,调用FtpClient类的listFiles(String pathName)方法时,抛如下异常:
Exception in thread "main" java.lang.NoClassDefFoundError:org/apache/oro/text/regex/MalformedPatternException
at org.apache.commons.net.ftp.parser.RegexFTPFileEntryParserImpl. (RegexFTPFileEntryParserImpl.java:75)
at org.apache.commons.net.ftp.parser.ConfigurableFTPFileEntryParserImpl.(ConfigurableFTPFileEntryParserImpl.java:57)
at org.apache.commons.net.ftp.parser.UnixFTPEntryParser.(UnixFTPEntryParser.java:136)
at org.apache.commons.net.ftp.parser.UnixFTPEntryParser.(UnixFTPEntryParser.java:119)
at org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory.createUnixFTPEntryParser(DefaultFTPFileEntryParserFactory.java:169)
at org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory.createFileEntryParser(DefaultFTPFileEntryParserFactory.java:94)
at org.apache.commons.net.ftp.FTPClient.initiateListParsing(FTPClient.java:2358)
at org.apache.commons.net.ftp.FTPClient.listFiles(FTPClient.java:2141)
at org.apache.commons.net.ftp.FTPClient.listFiles(FTPClient.java:2188)
.................
以上异常是由于缺少辅助的包jakarta-oro-2.0.8.jar引起的,去http://commons.apache.com/网站下载该包后放入工程的lib下,并加载到classpath中,重新编译运行,OK!
二、调用FtpClient类的listFiles(String pathName)方法失效的问题:
一般是由于ftp服务器(主要是小型机)的操作系统不同语言环境的时间格式造成的,在中文环境下,文件或文件夹的时间格式为"m月d日 hh:mm"或"yyyy年m月 d",而E文环境下时间格式为"MMM d yyyy"或"MMM d HH:mm",于是,在中文环境下,ftp包中的FTPTimestampParserImpl类将时间字符串Date化时抛异常,因为commons-net-1.4.1包不支持中文。
解决办法(两种办法):
1. 将ftp服务器操作系统语言环境设为英文;
2. 修改ftp包的代码:将FTPTimestampParserImpl类进行扩展,使之支持中文
下面针对第2种解决办法来实现:
(1) 新建类FTPTimestampParserImplExZH类:
1
/**2
* FTPTimestampParserImpl的扩展类,使之支持中文环境的时间格式3
* Date:2007-8-154
*/5
packageorg.apache.commons.net.ftp.parser;6
7
importjava.text.ParseException;8
importjava.text.ParsePosition;9
importjava.text.SimpleDateFormat;10
importjava.util.Calendar;11
importjava.util.Date;12
13
/**14
*@authorhzwei20615
* FTPTimestampParserImpl的扩展类,使之支持中文环境的时间格式16
*/17
publicclassFTPTimestampParserImplExZHextendsFTPTimestampParserImpl18
{19
privateSimpleDateFormat defaultDateFormat=newSimpleDateFormat("mm d hh:mm");20
privateSimpleDateFormat recentDateFormat=newSimpleDateFormat("yyyy mm d");21
22
/**23
*@authorhzwei20624
* 将中文环境的时间格式进行转换25
*/26
privateString formatDate_Zh2En(String timeStrZh)27
{28
if(timeStrZh==null)29
{30
return"";31
}32
33
intlen=timeStrZh.length();34
StringBuffer sb=newStringBuffer(len);35
charch='';36
for(inti=0;i{38
ch=timeStrZh.charAt(i);39
if((ch>='0'&&ch<='9')||ch==''||ch==':')40
{41
sb.append(ch);42
}43
}44
45
returnsb.toString();46
}47
48
/**49
* Implements the one {@linkFTPTimestampParser#parseTimestamp(String) method}50
* in the {@linkFTPTimestampParser FTPTimestampParser} interface51
* according to this algorithm:52
*53
* If the recentDateFormat member has been defined, try to parse the54
* supplied string with that. If that parse fails, or if the recentDateFormat55
* member has not been defined, attempt to parse with the defaultDateFormat56
* member. If that fails, throw a ParseException.57
*58
*@seeorg.apache.commons.net.ftp.parser.FTPTimestampParser#parseTimestamp(java.lang.String)59
*/60
publicCalendar parseTimestamp(String timestampStr)throwsParseException61
{62
timestampStr=formatDate_Zh2En(timestampStr);63
Calendar now=Calendar.getInstance();64
now.setTimeZone(this.getServerTimeZone());65
66
Calendar working=Calendar.getInstance();67
working.setTimeZone(this.getServerTimeZone());68
ParsePosition pp=newParsePosition(0);69
70
Date parsed=null;71
if(this.recentDateFormat!=null)72
{73
parsed=recentDateFormat.parse(timestampStr, pp);74
}75
if(parsed!=null&&pp.getIndex()==timestampStr.length())76
{77
working.setTime(parsed);78
working.set(Calendar.YEAR, now.get(Calendar.YEAR));79
if(working.after(now))80
{81
working.add(Calendar.YEAR,-1);82
}83
}84
else85
{86
pp=newParsePosition(0);87
parsed=defaultDateFormat.parse(timestampStr, pp);88
//note, length checks are mandatory for us since89
//SimpleDateFormat methods will succeed if less than90
//full string is matched. They will also accept,91
//despite "leniency" setting, a two-digit number as92
//a valid year (e.g. 22:04 will parse as 22 A.D.)93
//so could mistakenly confuse an hour with a year,94
//if we don't insist on full length parsing.95
if(parsed!=null&&pp.getIndex()==timestampStr.length())96
{97
working.setTime(parsed);98
}99
else100
{101
thrownewParseException(102
"Timestamp could not be parsed with older or recent DateFormat",103
pp.getIndex());104
}105
}106
returnworking;107
}108
}109
110
111
(2)修改org.apache.commons.net.ftp.parser.UnixFTPEntryParser类的parseFTPEntry方法:
1
publicFTPFile parseFTPEntry(String entry)2
{3
..4
if(matches(entry))5
{6
String typeStr=group(1);7
String hardLinkCount=group(15);8
String usr=group(16);9
String grp=group(17);10
String filesize=group(18);11
String datestr=group(19)+""+group(20);12
String name=group(21);13
String endtoken=group(22);14
15
try16
{17
file.setTimestamp(super.parseTimestamp(datestr));18
}19
catch(ParseException e)20
{21
/****mod by hzwei206 将中文时间格式转换 2007-8-15 begin****/22
//return null;//this is a parsing failure too.23
try24
{25
FTPTimestampParserImplExZH Zh2En=newFTPTimestampParserImplExZH();26
file.setTimestamp(Zh2En.parseTimestamp(datestr));27
}28
catch(ParseException e1)29
{30
returnnull;//this is a parsing failure too.31
}32
/****mod by hzwei206 将中文时间格式转换 2007-8-15 end****/33
}34
35
..36
}37
JAVA中使用FTPClient上传下载
在JAVA程序中,经常需要和FTP打交道,比如向FTP服务器上传文件、下载文件,本文简单介绍如何利用jakarta commons中的FTPClient(在commons-net包中)实现上传下载文件。
一、上传文件
原理就不介绍了,大家直接看代码吧
/**
* Description: 向FTP服务器上传文件
* @Version1.0 Jul 27, 2008 4:31:09 PM by 崔红保(cuihongbao@d-heaven.com)创建
* @param url FTP服务器hostname
* @param port FTP服务器端口
* @param username FTP登录账号
* @param password FTP登录密码
* @param path FTP服务器保存目录
* @param filename 上传到FTP服务器上的文件名
* @param input 输入流
* @return 成功返回true,否则返回false
*/
publicstaticbooleanuploadFile(String url,intport,String username, String password, String path, String filename, InputStream input) {
booleansuccess =false;
FTPClient ftp = newFTPClient();
try{
intreply;
ftp.connect(url, port);//连接FTP服务器
//如果采用默认端口,可以使用ftp.connect(url)的方式直接连接FTP服务器
ftp.login(username, password);//登录
reply = ftp.getReplyCode();
if(!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
returnsuccess;
}
ftp.changeWorkingDirectory(path);
ftp.storeFile(filename, input);
input.close();
ftp.logout();
success = true;
} catch(IOException e) {
e.printStackTrace();
} finally{
if(ftp.isConnected()) {
try{
ftp.disconnect();
} catch(IOException ioe) {
}
}
}
returnsuccess;
}
下面我们写两个小例子:
1.将本地文件上传到FTP服务器上,代码如下:
@Test
publicvoidtestUpLoadFromDisk(){
try{
FileInputStream in=newFileInputStream(newFile("D:/test.txt"));
booleanflag = uploadFile("127.0.0.1",21,"test","test","D:/ftp","test.txt", in);
System.out.println(flag);
} catch(FileNotFoundException e) {
e.printStackTrace();
}
}
2.在FTP服务器上生成一个文件,并将一个字符串写入到该文件中
@Test
publicvoidtestUpLoadFromString(){
try{
InputStream input = newByteArrayInputStream("test ftp".getBytes("utf-8"));
booleanflag = uploadFile("127.0.0.1",21,"test","test","D:/ftp","test.txt", input);
System.out.println(flag);
} catch(UnsupportedEncodingException e) {
e.printStackTrace();
}
}
二、下载文件
从FTP服务器下载文件的代码也很简单,参考如下:
/**
* Description: 从FTP服务器下载文件
* @Version1.0 Jul 27, 2008 5:32:36 PM by 崔红保(cuihongbao@d-heaven.com)创建
* @param url FTP服务器hostname
* @param port FTP服务器端口
* @param username FTP登录账号
* @param password FTP登录密码
* @param remotePath FTP服务器上的相对路径
* @param fileName 要下载的文件名
* @param localPath 下载后保存到本地的路径
* @return
*/
publicstaticbooleandownFile(String url,intport,String username, String password, String remotePath,String fileName,String localPath) {
booleansuccess =false;
FTPClient ftp = newFTPClient();
try{
intreply;
ftp.connect(url, port);
//如果采用默认端口,可以使用ftp.connect(url)的方式直接连接FTP服务器
ftp.login(username, password);//登录
reply = ftp.getReplyCode();
if(!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
returnsuccess;
}
ftp.changeWorkingDirectory(remotePath);//转移到FTP服务器目录
FTPFile[] fs = ftp.listFiles();
for(FTPFile ff:fs){
if(ff.getName().equals(fileName)){
File localFile = newFile(localPath+"/"+ff.getName());
OutputStream is = newFileOutputStream(localFile);
ftp.retrieveFile(ff.getName(), is);
is.close();
}
}
ftp.logout();
success = true;
} catch(IOException e) {
e.printStackTrace();
} finally{
if(ftp.isConnected()) {
try{
ftp.disconnect();
} catch(IOException ioe) {
}
}
}
returnsuccess;
}