<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆 - 1  文章 - 1  trackbacks - 0
    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    常用鏈接

    留言簿(2)

    隨筆檔案

    搜索

    •  

    最新評論

     

        目前開發(fā)的這個項目中需要從遠程服務器上下載數(shù)據(jù),采用了開源的commons.net.ftp包。在實際應用中發(fā)現(xiàn)了一個問題,在測試服務器上調(diào)用ftpClient.listFiles()方法可以返回包含文件名的數(shù)組,而在現(xiàn)網(wǎng)服務器上此方法返回NULL。我被這個問題困擾了好久,下面把我的處理思路陳述如下:

    1)首先發(fā)現(xiàn)2個服務器的區(qū)別:測試服務器為solaris服務器,而現(xiàn)網(wǎng)服務器為hp服務器,會不會是平臺差異所致呢?帶著這個問題,下載了common包的源碼,通過源碼進行調(diào)試。

    2FTPListParseEngine負責處理通過socket來獲取遠程服務器的信息。大概執(zhí)行了ls –l

    操作,并把結(jié)果一行行放入一個linkedlist中。代碼如下:

     1private void readStream(InputStream stream, String encoding) throws IOException
     2    {
     3        BufferedReader reader;
     4        if (encoding == null)
     5        {
     6            reader = new BufferedReader(new InputStreamReader(stream));
     7        }

     8        else
     9        {
    10            reader = new BufferedReader(new InputStreamReader(stream, encoding));
    11        }

    12        
    13        String line = this.parser.readNextEntry(reader);
    14
    15        while (line != null)
    16        {
    17            this.entries.add(line);
    18            line = this.parser.readNextEntry(reader);
    19        }

    20        reader.close();
    21    }

    22

     

    3)這個時候發(fā)現(xiàn)問題了,傳入line中的字符串中有亂碼!正常的應該為:

    drwxr-xr-x 11 daladmin   daladmin      1024 2004年918 mqm


    其中時間那部分為亂碼。                 

    4)處理:在調(diào)用listFiles()之前先調(diào)用ftpClient.setControlEncoding("GBK");這樣line就能正常顯示了,但是listFiles() 返回依然為空!!! 繼續(xù).....

    (5) 發(fā)現(xiàn)繼續(xù)運行的時候有一個正則表達式匹配不成功,代碼如下:

     1 public boolean matches(String s)
     2    {
     3        this.result = null;
     4        if (_matcher_.matches(s.trim(), this.pattern))
     5        {
     6            this.result = _matcher_.getMatch();
     7        }

     8        return null != this.result;
     9    }

    10

     

    s即為(3)中的line,追蹤正則表達式,是在具體的子類UnixFTPEntryParser中寫死的。如下:

     1private static final String REGEX =
     2        "([bcdlfmpSs-])"
     3        +"(((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-])))\\+?\\s+"
     4        + "(\\d+)\\s+"
     5        + "(\\S+)\\s+"
     6        + "(?:(\\S+)\\s+)?"
     7        + "(\\d+)\\s+"
     8        
     9        /*
    10          numeric or standard format date
    11        */

    12        //問題出在此處,這個匹配只匹配2中形式:
    13        //(1)2008-08-03
    14        //(2)Jan  9或4月 26
    15        //而出錯的hp機器下的顯示為 8月20日(沒有空格分開)
    16        //故無法匹配而報錯
    17        //將下面字符串改為:
    18        //((?:\\d+[-/]\\d+[-/]\\d+)|(?:\\S+\\s+\\S+)|(?:\\S+))\\s+
    19        //便可以成功匹配
    20        + "((?:\\d+[-/]\\d+[-/]\\d+)|(?:\\S+\\s+\\S+))\\s+"
    21        
    22        /* 
    23           year (for non-recent standard format) 
    24           or time (for numeric or recent standard format  
    25        */

    26        + "(\\d+(?::\\d+)?)\\s+"
    27        
    28        + "(\\S*)(\\s*.*)";
    29

     

    6)做上面修改后,能夠解析出來,但是接著又會報異常,錯誤發(fā)生在UnixFTPEntryParser類的parseFTPEntry方法中,common.net對中文支持的實在是不夠:

     1 try
     2            {
     3                file.setTimestamp(super.parseTimestamp(datestr));
     4            }

     5            catch (ParseException e)
     6            {
     7            //注釋掉
     8                return null;  // this is a parsing failure too.
     9            }

    10

     

    這個錯誤的原因是創(chuàng)建simpleDateFormat類時(詳情請見jdkAPI文檔)

    public SimpleDateFormat(String pattern, Locale locale)

     

    localeEN,解決方案是創(chuàng)建一個新類,繼承ConfigurableFTPFileEntryParserImpl。其中的屬性defaultDateFormatrecentDateFormat Locale.CHINA初始化。而我目前的程序用不到取文件的修改時間,所以直接省事將上段代碼中的異常吞掉,即注釋掉return null 。網(wǎng)上有個解決方案(http://hi.baidu.com/hzwei206/blog/item/7c901d2debf7e136359bf7cd.html,是用了另一種方案,粘貼如下:
     

     

    commons-net-1.4.1.jar包中ftp應用的幾點問題


    一、異常:
             從http://commons.apache.com網(wǎng)站下載了commons-net-1.4.1包后添加到自己的工程中,調(diào)用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.<init> (RegexFTPFileEntryParserImpl.java:75)
                   at org.apache.commons.net.ftp.parser.ConfigurableFTPFileEntryParserImpl.<init>(ConfigurableFTPFileEntryParserImpl.java:57)
                   at org.apache.commons.net.ftp.parser.UnixFTPEntryParser.<init>(UnixFTPEntryParser.java:136)
                   at org.apache.commons.net.ftp.parser.UnixFTPEntryParser.<init>(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網(wǎng)站下載該包后放入工程的lib下,并加載到classpath中,重新編譯運行,OK!

    二、調(diào)用FtpClient類的listFiles(String pathName)方法失效的問題:
          一般是由于ftp服務器(主要是小型機)的操作系統(tǒng)不同語言環(huán)境的時間格式造成的,在中文環(huán)境下,文件或文件夾的時間格式為"m月d日 hh:mm"或"yyyy年m月 d",而E文環(huán)境下時間格式為"MMM d yyyy"或"MMM d HH:mm",于是,在中文環(huán)境下,ftp包中的FTPTimestampParserImpl類將時間字符串Date化時拋異常,因為commons-net-1.4.1包不支持中文。
    解決辦法(兩種辦法):
            1. 將ftp服務器操作系統(tǒng)語言環(huán)境設為英文;
             2. 修改ftp包的代碼:將FTPTimestampParserImpl類進行擴展,使之支持中文
    下面針對第2種解決辦法來實現(xiàn):
    (1)    新建類FTPTimestampParserImplExZH類:

      1/**
      2* FTPTimestampParserImpl的擴展類,使之支持中文環(huán)境的時間格式
      3* Date:2007-8-15
      4*/

      5package org.apache.commons.net.ftp.parser;
      6
      7import java.text.ParseException;
      8import java.text.ParsePosition;
      9import java.text.SimpleDateFormat;
     10import java.util.Calendar;
     11import java.util.Date;
     12
     13/**
     14@author hzwei206
     15* FTPTimestampParserImpl的擴展類,使之支持中文環(huán)境的時間格式
     16*/

     17public class FTPTimestampParserImplExZH extends FTPTimestampParserImpl
     18{
     19      private SimpleDateFormat defaultDateFormat = new SimpleDateFormat("mm d hh:mm");
     20      private SimpleDateFormat recentDateFormat = new SimpleDateFormat("yyyy mm d");
     21
     22      /**
     23       * @author hzwei206
     24       * 將中文環(huán)境的時間格式進行轉(zhuǎn)換
     25       */

     26      private String formatDate_Zh2En(String timeStrZh)
     27      {
     28          if (timeStrZh == null)
     29          {
     30              return "";
     31          }

     32        
     33          int len = timeStrZh.length();
     34          StringBuffer sb = new StringBuffer(len);
     35          char ch = ' ';
     36          for (int i = 0;i < len;i++)
     37          {
     38              ch = timeStrZh.charAt(i);
     39              if ((ch >= '0' && ch <= '9'|| ch == ' ' || ch == ':')
     40              {
     41                  sb.append(ch);
     42              }

     43          }

     44        
     45          return sb.toString();
     46      }

     47    
     48      /** 
     49       * Implements the one {@link    FTPTimestampParser#parseTimestamp(String)    method}
     50       * in the {@link    FTPTimestampParser    FTPTimestampParser} interface 
     51       * according to this algorithm:
     52       * 
     53       * If the recentDateFormat member has been defined, try to parse the 
     54       * supplied string with that.    If that parse fails, or if the recentDateFormat
     55       * member has not been defined, attempt to parse with the defaultDateFormat
     56       * member.    If that fails, throw a ParseException. 
     57       * 
     58       * @see org.apache.commons.net.ftp.parser.FTPTimestampParser#parseTimestamp(java.lang.String)  
     59       */

     60      public Calendar parseTimestamp(String timestampStr) throws ParseException
     61      {
     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 = new ParsePosition(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          else
     85          {
     86              pp = new ParsePosition(0);
     87              parsed = defaultDateFormat.parse(timestampStr, pp);
     88              // note, length checks are mandatory for us since
     89              // SimpleDateFormat methods will succeed if less than
     90              // full string is matched. They will also accept,
     91              // despite "leniency" setting, a two-digit number as
     92              // 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              else
    100              {
    101                  throw new ParseException(
    102                          "Timestamp could not be parsed with older or recent DateFormat",
    103                          pp.getIndex());
    104              }

    105          }

    106          return working;
    107      }

    108}

    109
    110
    111


    (2) 修改org.apache.commons.net.ftp.parser.UnixFTPEntryParser類的parseFTPEntry方法:
         

     1 public FTPFile 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              try
    16              {
    17                  file.setTimestamp(super.parseTimestamp(datestr));
    18              }

    19              catch (ParseException e)
    20              {
    21                  /* ***mod by hzwei206 將中文時間格式轉(zhuǎn)換 2007-8-15 begin*** */
    22                  //return null; // this is a parsing failure too.
    23                  try
    24                  {
    25                      FTPTimestampParserImplExZH Zh2En = new FTPTimestampParserImplExZH();
    26                      file.setTimestamp(Zh2En.parseTimestamp(datestr));
    27                  }

    28                  catch (ParseException e1)
    29                  {
    30                      return null// this is a parsing failure too.
    31                  }

    32                  /* ***mod by hzwei206 將中文時間格式轉(zhuǎn)換 2007-8-15 end*** */
    33              }

    34
    35              ..
    36      }

    37

    posted on 2008-08-21 21:30 wodong 閱讀(14940) 評論(1)  編輯  收藏

    FeedBack:
    # 150 Here comes the directory listing[未登錄] 2012-06-08 15:45 cnwong
    還有可能存在的現(xiàn)象:卡死在“150 Here comes the directory listing.”一行不再往下執(zhí)行,說明FTPClient.class -->socket=server.accept()被鎖死,原因是FTPClient.class -->getActivePort()返回了0,而你linux客戶端又恰巧不開放該端口。將getActivePort()的返回值設置成linux客戶端開放的且未被占用的端口值即可(一般是80XX)。  回復  更多評論
      

    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導航:
     
    主站蜘蛛池模板: 天天天欲色欲色WWW免费| 国产曰批免费视频播放免费s| 国产色无码精品视频免费| 成全动漫视频在线观看免费高清版下载 | 国产一区二区三区免费在线观看 | 男女啪啪永久免费观看网站| 国产免费AV片无码永久免费| 亚洲中文字幕不卡无码| 亚洲精品资源在线| 亚洲成aⅴ人片久青草影院按摩| 深夜久久AAAAA级毛片免费看| 久久免费动漫品精老司机| 男男AV纯肉无码免费播放无码| 免费一级毛片在线播放| 国产亚洲精品va在线| 亚洲中字慕日产2020| 一区二区三区免费高清视频| 最近2019中文字幕免费大全5 | 香蕉视频在线观看免费国产婷婷| 亚洲精品无码久久不卡| 97se亚洲综合在线| 国产av无码专区亚洲av毛片搜| 国偷自产一区二区免费视频| 最近最新的免费中文字幕| 国产国拍精品亚洲AV片| 亚洲日本久久一区二区va| 一级一级毛片免费播放| 在线视频精品免费| 亚洲真人无码永久在线| 亚洲人成综合网站7777香蕉| 国产精品免费久久久久影院| 久久99九九国产免费看小说| 亚洲综合另类小说色区色噜噜| 亚洲欧洲精品在线| 国产精品九九久久免费视频 | 亚洲日韩精品无码一区二区三区| 亚洲av永久无码精品三区在线4 | 99热在线免费播放| 亚洲第一区精品观看| 亚洲国产精品综合久久2007| 国产福利免费视频|