中文FTP環境下,使用commons-net,FTPClient.listFiles()方法返回null的問題及解決辦法...

項目中需要從FTP上下載數據,採用了開源的commons-net包。在實際應用中發現了一個問題,有些服務器上調用ftpClient.listFiles()方法可以返回包含文件名的數組,有些服務器上此方法返回NULL。但是ftpClient.listNames()方法能返回路徑中的文件名,ftpClient.delete()方法也能刪除文件。
命令行連接FTP,執行ls -l 發現返回數據日期的地方比較奇怪。
[quote]-rw-rw-rw- 1 username nobody 145 6月22 16時56 xxxxx.csv
drw-rw-rw- 1 username nobody 145 6月22 2010 bak_dir[/quote]

失敗原因就是這裏,commons-net包的FTPListParseEngine負責處理通過socket來獲取遠程服務器的信息。通過ls –l的信息,解析出文件名,文件時間,文件大小,文件權限,文件創建者。。。。。
  public FTPFile[] getFiles() throws IOException {
List tmpResults = new LinkedList();
Iterator iter = this.entries.iterator();
while (iter.hasNext()) {
String entry = (String) iter.next();
// 核心方法
// commons-net默認根據機器信息,按照Unix,WinNT返回解析結果,
// 解析方法通過正則表達式,區分匹配各個字段,不支持中文日期,
FTPFile temp = this.parser.parseFTPEntry(entry);
tmpResults.add(temp);
}
return (FTPFile[]) tmpResults.toArray(new FTPFile[0]);
}

 
//listFiles方法先初始化FTPListParseEngine,initiateListParsing方法
public FTPFile[] listFiles(String pathname) throws IOException{
String key = null;
FTPListParseEngine engine = initiateListParsing(key, pathname);
return engine.getFiles();
}

public FTPListParseEngine initiateListParsing(String parserKey, String pathname)
throws IOException {
if (__entryParser == null) {
// 傳遞parserKey的方法deprecated了,推薦使用FTPClientConfig
if (null != parserKey) {
__entryParser = __parserFactory.createFileEntryParser(parserKey);
}
// 設置了FTPClientConfig,按照設置生成ParseEngine
else {
if (null != __configuration) {
__entryParser = __parserFactory.createFileEntryParser(__configuration);
}
// 默認情況下,根據機器信息,自動生成ParseEngine
else {
__entryParser = __parserFactory.createFileEntryParser(getSystemName());
}
}
}
return initiateListParsing(__entryParser, pathname);
}



找到原因後,我們有的放矢,具體解析-rw-rw-rw- 1 username nobody 145 6月22 16時56 xxxxx.csv一行數據
/**
* <pre>
* 解析IBM財務FTP服務器返回的一行信息
* -rw-rw-rw- 1 chnnlftp nobody 145 6月22 16時56 finance_back_info_20100617150652.csv
* 取得文件名,文件時間,文件類型,文件大小,文件所屬用戶。
*
* 本程序不具有複用性!!
* </pre>
*/
public class MyFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {

private Class clazz = MyFTPEntryParser.class;
private Log log = LogFactory.getLog(clazz);

/**
* 解析FTP傳回的文件信息
*/
public FTPFile parseFTPEntry(String entry) {
log.debug("開始解析,內容爲: " + entry);

FTPFile file = new FTPFile();
file.setRawListing(entry);

String[] temp = entry.split("\\s+");
if (temp.length != 8) {
return null;
}
String fileType = temp[0].substring(0, 1);
if ("d".equals(fileType)) {
file.setType(FTPFile.DIRECTORY_TYPE);
} else {
file.setType(FTPFile.FILE_TYPE);
file.setSize(Integer.valueOf(temp[4]));
}
file.setName(temp[7]);
file.setUser(temp[3]);

Calendar date = Calendar.getInstance();
Date fileDate;
// 返回【6月22 2010】形式的日期
if(temp[6].matches("\\d{4}")){
try {
fileDate = new SimpleDateFormat("yyyyMM月dd")
.parse(temp[6] + temp[5]);
} catch (ParseException e) {
throw new RuntimeException("日期解析出錯", e);
}
// 返回【6月22 16時56】形式的日期
} else {
int yyyy = date.get(Calendar.YEAR);
try {
fileDate = new SimpleDateFormat("yyyyMM月ddHH時mm")
.parse(yyyy + temp[5] + temp[6]);
} catch (ParseException e) {
throw new RuntimeException("日期解析出錯", e);
}
}
date.setTime(fileDate);
file.setTimestamp(date);

return file;
}

// =====================================================================
// 本類只是特定解析一種FTP,沒有考慮到使用正則表達式,匹配解析一類FTP
// 核心方法爲parseFTPEntry,以下方法沒有實現。
// =====================================================================
public MyFTPEntryParser() {
this("");
}

public MyFTPEntryParser(String regex) {
super("");
}

protected FTPClientConfig getDefaultConfiguration() {
return new FTPClientConfig(clazz.getPackage().getName()
+ clazz.getSimpleName(), "", "", "", "", "");
}
}



// 在調用 ftpClient.listNames()方法前,先調用
ftpClient.configure(new FTPClientConfig(package.MyFTPEntryParser));
// package.MyFTPEntryParser:我們的類的全路徑



參考:
http://www.blogjava.net/wodong/archive/2008/08/21/wodong.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章