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

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

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

    隨筆 - 1  文章 - 1  trackbacks - 0
    <2012年6月>
    272829303112
    3456789
    10111213141516
    17181920212223
    24252627282930
    1234567

    常用鏈接

    留言簿(2)

    隨筆檔案

    搜索

    •  

    最新評論

     

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

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

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

    操作,并把結果一行行放入一個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)這個時候發現問題了,傳入line中的字符串中有亂碼!正常的應該為:

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


    其中時間那部分為亂碼。                 

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

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

     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)做上面修改后,能夠解析出來,但是接著又會報異常,錯誤發生在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

     

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

    public SimpleDateFormat(String pattern, Locale locale)

     

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

     

    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.<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網站下載該包后放入工程的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-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的擴展類,使之支持中文環境的時間格式
     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       * 將中文環境的時間格式進行轉換
     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 將中文時間格式轉換 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 將中文時間格式轉換 2007-8-15 end*** */
    33              }

    34
    35              ..
    36      }

    37

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

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

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


    網站導航:
     
    主站蜘蛛池模板: 偷自拍亚洲视频在线观看| 免费可以在线看A∨网站| 国产成人亚洲精品播放器下载 | 久久久久亚洲av无码专区| 国产又粗又猛又爽又黄的免费视频| 最近免费中文字幕mv在线电影| 久草免费福利在线| 国产成人综合亚洲绿色| 国产精品亚洲四区在线观看| 午夜亚洲国产理论秋霞| 337p日本欧洲亚洲大胆裸体艺术 | 亚洲中文字幕一二三四区苍井空| 亚洲va无码va在线va天堂| 亚洲第一成人影院| 国产无遮挡吃胸膜奶免费看| 99精品国产免费久久久久久下载| 久久亚洲免费视频| 男女午夜24式免费视频| a级在线免费观看| 亚洲精品视频免费 | 亚洲毛片不卡av在线播放一区| 午夜寂寞在线一级观看免费| 久草视频免费在线| **aaaaa毛片免费同男同女| 一区二区免费视频| 免费成人在线视频观看| 91福利免费网站在线观看| 精品国产呦系列在线观看免费 | 在线观看人成网站深夜免费| 成人毛片免费观看视频在线| 日韩免费精品视频| 麻豆一区二区免费播放网站| 中文字幕无码不卡免费视频| 中字幕视频在线永久在线观看免费| 精品国产污污免费网站aⅴ| 永久黄色免费网站| 精品久久久久成人码免费动漫| 成年女人毛片免费观看97| 日本免费中文字幕在线看| 免费a级毛片大学生免费观看 | 免费一级毛片在线播放放视频|