起因:最近通过FTP接收第三方客户的日志,发现当他们的ftp服务器的文件时间为中文时:
如下格式:
rw-r----- 1 cmodftp boss3 0 7月26日 16:23 LP_OPERATION_LOG_20120417.done
-rw-r--r-- 1 boss3adm boss3 32037633 2012年4月17日 LP_OPERATION_LOG_20120417.log
-rw-r--r-- 1 boss3adm boss3 43843978 2012年5月17日 LP_OPERATION_LOG_20120517.csv
-rw-r--r-- 1 boss3adm boss3 42120155 2012年6月17日 LP_OPERATION_LOG_20120617.csv
-rw-r--r-- 1 boss3adm boss3 41001090 2012年7月17日 LP_OPERATION_LOG_20120717.csv
-rw-r--r-- 1 boss3adm boss3 45539206 2012年8月17日 LP_OPERATION_LOG_20120817.csv
-rw-r--r-- 1 boss3adm boss3 29434197 2012年9月17日 LP_OPERATION_LOG_20120917.csv
-rw-r--r-- 1 boss3adm boss3 22358774 2012年10月17日 LP_OPERATION_LOG_20121017.csv
-rw-r--r-- 1 boss3adm boss3 9104535 2012年11月17日 LP_OPERATION_LOG_20121117.csv
-rw-r--r-- 1 boss3adm boss3 13295291 2012年12月17日 LP_OPERATION_LOG_20121217.csv
-rw-r--r-- 1 boss3adm boss3 13490257 2013年1月17日 LP_OPERATION_LOG_20130117.csv
-rw-r--r-- 1 boss3adm boss3 33587905 2月17日 06:15 LP_OPERATION_LOG_20130217.csv
-rw-r--r-- 1 boss3adm boss3 24715688 3月17日 06:04 LP_OPERATION_LOG_20130317.csv
-rw-r--r-- 1 boss3adm boss3 23283526 4月17日 07:24 LP_OPERATION_LOG_20130417.csv
-rw-r--r-- 1 boss3adm boss3 27248855 5月17日 07:36 LP_OPERATION_LOG_20130517.csv
-rw-r--r-- 1 boss3adm boss3 21768020 7月17日 06:58 LP_OPERATION_LOG_20130717.csv
在接收时,无法获取该目录下的文件列表。
查看源代码如下:
package org.apache.commons.net.ftp.parser;
public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
{
private static final String REGEX =
"([bcdelfmpSs-])"
+"(((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-])))\\+?\\s*"
+ "(\\d+)\\s+" // link count
+ "(?:(\\S+(?:\\s\\S+)*?)\\s+)?" // owner name (optional spaces)
+ "(?:(\\S+(?:\\s\\S+)*)\\s+)?" // group name (optional spaces)
+ "(\\d+(?:,\\s*\\d+)?)\\s+" // size or n,m
/*
* numeric or standard format date:
* yyyy-mm-dd (expecting hh:mm to follow)
* MMM [d]d
* [d]d MMM
* N.B. use non-space for MMM to allow for languages such as German which use
* diacritics (e.g. umlaut) in some abbreviations.
*/
//+ "((?:\\d+[-/]\\d+[-/]\\d+)|(?:\\S{3}\\s+\\d{1,2})|(?:\\d{1,2}\\s+\\S{3}))\\s+"
// to support the date of ‘2013年2月12日’ or ‘3月17日’ ---------> kavin 21030801
//此处添加了((?:\\d{1,4}\\u5e74{1})?\\d{1,2}\\u6708{1}\\d{1,2}\\u65e5{1})支持中文日期格式
+ "(((?:\\d{1,4}\\u5e74{1})?\\d{1,2}\\u6708{1}\\d{1,2}\\u65e5{1})|(?:\\d+[-/]\\d+[-/]\\d+)|(?:\\S{3}\\s+\\d{1,2})|(?:\\d{1,2}\\s+\\S{3}))\\s+"
/*
year (for non-recent standard format) - yyyy
or time (for numeric or recent standard format) [h]h:mm
*/
//+ "(\\d+(?::\\d+)?)\\s+"
+ "((\\d+(?::\\d+)?)\\s+)?"
+ "(\\S*)(\\s*.*)"; // the rest
}
/**
* Parses a line of a unix (standard) FTP server file listing and converts
* it into a usable format in the form of an <code> FTPFile </code>
* instance. If the file listing line doesn't describe a file,
* <code> null </code> is returned, otherwise a <code> FTPFile </code>
* instance representing the files in the directory is returned.
* <p>
* @param entry A line of text from the file listing
* @return An FTPFile instance corresponding to the supplied entry
*/
// @Override
public FTPFile parseFTPEntry(String entry) {
FTPFile file = new FTPFile();
file.setRawListing(entry);
int type;
boolean isDevice = false;
if (matches(entry))
{
int groupCount = getGroupCnt();
String typeStr = group(1);
String hardLinkCount = group(15);
String usr = group(16);
String grp = group(17);
String filesize = group(18);
String datestr = group(19) + " " + group(21);
String name = group(24);
switch (groupCount)
{
// Jul 24 00:55
case 24:
if(datestr.contains("\u65e5"))
{
datestr = group(19);
name = group(23);
}
break;
default:
break;
}
String endtoken = null;
try
{
System.out.println(" ------------------------> groupCount = "+groupCount+" | datestr = "+datestr +" <-----------------------");
file.setTimestamp(super.parseTimestamp(datestr));
}
catch (ParseException e)
{
/* ***mod by kavin将中文时间格式转换 2013-7-31 begin*** */
//return null; // this is a parsing failure too.
try
{
FTPTimestampParserImplExZH Zh2En = new FTPTimestampParserImplExZH();
file.setTimestamp(Zh2En.parseTimestamp(datestr));
}
catch (ParseException e1)
{
//e1.printStackTrace();
return null; // this is a parsing failure too.
}
}
// A 'whiteout' file is an ARTIFICIAL entry in any of several types of
// 'translucent' filesystems, of which a 'union' filesystem is one.
// bcdelfmpSs-
switch (typeStr.charAt(0))
{
case 'd':
type = FTPFile.DIRECTORY_TYPE;
break;
case 'e': // NET-39 => z/OS external link
type = FTPFile.SYMBOLIC_LINK_TYPE;
break;
case 'l':
type = FTPFile.SYMBOLIC_LINK_TYPE;
break;
case 'b':
case 'c':
isDevice = true;
type = FTPFile.FILE_TYPE; // TODO change this if DEVICE_TYPE implemented
break;
case 'f':
case '-':
type = FTPFile.FILE_TYPE;
break;
default: // e.g. ? and w = whiteout
type = FTPFile.UNKNOWN_TYPE;
}
file.setType(type);
int g = 4;
for (int access = 0; access < 3; access++, g += 4)
{
// Use != '-' to avoid having to check for suid and sticky bits
file.setPermission(access, FTPFile.READ_PERMISSION,
(!group(g).equals("-")));
file.setPermission(access, FTPFile.WRITE_PERMISSION,
(!group(g + 1).equals("-")));
String execPerm = group(g + 2);
if (!execPerm.equals("-") && !Character.isUpperCase(execPerm.charAt(0)))
{
file.setPermission(access, FTPFile.EXECUTE_PERMISSION, true);
}
else
{
file.setPermission(access, FTPFile.EXECUTE_PERMISSION, false);
}
}
if (!isDevice)
{
try
{
file.setHardLinkCount(Integer.parseInt(hardLinkCount));
}
catch (NumberFormatException e)
{
// intentionally do nothing
}
}
file.setUser(usr);
file.setGroup(grp);
try
{
file.setSize(Long.parseLong(filesize));
}
catch (NumberFormatException e)
{
// intentionally do nothing
}
if (null == endtoken)
{
file.setName(name);
}
else
{
// oddball cases like symbolic links, file names
// with spaces in them.
name += endtoken;
if (type == FTPFile.SYMBOLIC_LINK_TYPE)
{
int end = name.indexOf(" -> ");
// Give up if no link indicator is present
if (end == -1)
{
file.setName(name);
}
else
{
file.setName(name.substring(0, end));
file.setLink(name.substring(end + 4));
}
}
else
{
file.setName(name);
}
}
return file;
}
return null;
}
新增加一个FTP文件时间解析类,专门处理中文时间,转换成正常的yyyyMMdd
public class FTPTimestampParserImplExZH extends FTPTimestampParserImpl
{
private SimpleDateFormat defaultDateFormat = new SimpleDateFormat("mm dd hh:mm");
private SimpleDateFormat recentDateFormat = new SimpleDateFormat("yyyy mm dd");
/**
* @author hzwei206 将中文环境的时间格式进行转换
*/
private String formatDate_Zh2En(String timeStrZh)
{
if (timeStrZh == null)
{
return "";
}
int len = timeStrZh.length();
StringBuffer sb = new StringBuffer(len);
char ch = ' ';
for (int i = 0; i < len; i++)
{
ch = timeStrZh.charAt(i);
if ((ch >= '0' && ch <= '9') || ch == ' ' || ch == ':')
{
sb.append(ch);
}
}
String timeDig = sb.toString();
int length = timeDig.length();
switch (length)
{
case 3:
timeDig = getToday("yyyy")+"0"+timeDig;
break;
case 4:
timeDig = getToday("yyyy")+timeDig;
break;
case 7:
timeDig = timeDig.substring(0, 4)+"0"+timeDig.substring(4);
break;
default:
break;
}
System.out.println(" ================>> formatDate_Zh2En<timeStrZh = "+timeStrZh+">|"+"<timeStr"+timeDig+">");
return timeDig;
}
private String getToday(String format)
{
if (format == null)
format = "yyyy-MM-dd HH:mm:ss";
Calendar c = Calendar.getInstance();
SimpleDateFormat ft = new SimpleDateFormat(format);
return ft.format(c.getTime());
}
/**
* Implements the one {@link FTPTimestampParser#parseTimestamp(String)
* method} in the {@link FTPTimestampParser FTPTimestampParser} interface
* according to this algorithm:
*
* If the recentDateFormat member has been defined, try to parse the
* supplied string with that. If that parse fails, or if the
* recentDateFormat member has not been defined, attempt to parse with the
* defaultDateFormat member. If that fails, throw a ParseException.
*
* @see org.apache.commons.net.ftp.parser.FTPTimestampParser#parseTimestamp(java.lang.String)
*/
public Calendar parseTimestamp(String timestampStr) throws ParseException
{
timestampStr = formatDate_Zh2En(timestampStr);
// Calendar now = Calendar.getInstance();
// now.setTimeZone(this.getServerTimeZone());
Calendar working = Calendar.getInstance();
int year = Integer.valueOf(timestampStr.substring(0, 4));
int month = Integer.valueOf(timestampStr.substring(4, 6));
int day = Integer.valueOf(timestampStr.substring(6, 8));
Calendar calendar = Calendar.getInstance();
calendar.set(year, month - 1, day, 0, 0, 0);
/* working.setTimeZone(this.getServerTimeZone());
ParsePosition pp = new ParsePosition(0);
Date parsed = null;
if (this.recentDateFormat != null)
{
parsed = recentDateFormat.parse(timestampStr, pp);
}
if (parsed != null && pp.getIndex() == timestampStr.length())
{
System.out.println("111111111111111111111111");
working.setTime(parsed);
working.set(Calendar.YEAR, now.get(Calendar.YEAR));
if (working.after(now))
{
working.add(Calendar.YEAR, -1);
}
}
else
{
System.out.println("22222222222222222222222");
pp = new ParsePosition(0);
parsed = defaultDateFormat.parse(timestampStr, pp);
// note, length checks are mandatory for us since
// SimpleDateFormat methods will succeed if less than
// full string is matched. They will also accept,
// despite "leniency" setting, a two-digit number as
// a valid year (e.g. 22:04 will parse as 22 A.D.)
// so could mistakenly confuse an hour with a year,
// if we don't insist on full length parsing.
if (parsed != null && pp.getIndex() == timestampStr.length())
{
working.setTime(parsed);
}
else
{
throw new ParseException("Timestamp could not be parsed with older or recent DateFormat", pp.getIndex());
}
}*/
return working;
}
}
通过以上方式即可获取列表,同时下载对应的文件。