`

中文FTP环境下,使用commons-net,FTPClient.listFiles()方法返回null的问题及解决办法

    博客分类:
  • Java
阅读更多
项目中需要从FTP上下载数据,采用了开源的commons-net包。在实际应用中发现了一个问题,有些服务器上调用ftpClient.listFiles()方法可以返回包含文件名的数组,有些服务器上此方法返回NULL。但是ftpClient.listNames()方法能返回路径中的文件名,ftpClient.delete()方法也能删除文件。
命令行连接FTP,执行ls -l 发现返回数据日期的地方比较奇怪。
引用
-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


失败原因就是这里,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
分享到:
评论

相关推荐

    Android的ftp下载示例

    可以使用`listFiles()`方法列出服务器上的文件,然后根据需要选择要下载的文件。假设我们有一个名为"downloaded_file.txt"的文件要下载: ```java String remoteFilePath = "/path/to/downloaded_file.txt"; FTP...

    FTP递归扫描文件到本地代码(Java)

    FTPFile[] files = ftpClient.listFiles(directoryPath); if (files != null && files.length &gt; 0) { // 目录不为空,继续扫描 for (FTPFile file : files) { String filePath = directoryPath + "/" + file....

    java实现Ftp批量下载文件及解压

    在Java编程环境中,FTP(File Transfer Protocol)是一个用于在计算机之间传输文件的标准协议。通过Java实现FTP批量下载文件以及解压的功能,可以极大地提高工作效率,特别是在处理大量数据时。以下是一份详细的步骤...

    java实现ftp自动上传文件

    在Java编程环境中,FTP(File Transfer Protocol)自动上传文件是一项常见的任务,特别是在自动化运维和数据交换的场景下。本文将详细讲解如何使用Java实现FTP自动上传整个磁盘的文件,包括目录结构,并介绍如何通过...

    java ftp 类

    此外,`listFiles()`方法可以用来获取远程目录下的文件列表,`changeWorkingDirectory()`用于切换工作目录,`makeDirectory()`用于创建新目录。 在完成所有FTP操作后,记得断开连接: ```java ftp.logout(); ftp....

    java操作FTP各种例子

    可以通过`listNames`或`listFiles`方法获取FTP服务器上的目录信息。 ```java String[] list = client.listNames(); for (String item : list) { System.out.println(item); } ``` 5. **创建、删除目录** `...

    Java实现FTP文件的上传和下载功能的实例代码

    FTPFile[] files = ftpClient.listFiles(remotePath); if (files == null || files.length == 0) { System.out.println("远程路径不存在"); return result; } // 打开本地文件输出流 File localFile = new ...

    java edftp 断点续传

    这通常通过调用`listNames()`或`listFiles()`方法来获取远程目录下的文件列表,然后通过`retrieveFile()`或`storeFile()`方法的返回值判断是否已经部分传输过。 4. **断点续传准备**:对于下载,你可以使用`...

    android文件上传fttp的各种操作代码实例.pdf

    `FTPFile[] remoteFiles = ftp.listFiles();`用于获取当前目录下的文件信息。 12. **加密解密**:`EncryptUtil.decode`方法用于解密服务器地址、用户名和密码,这可能是为了保护敏感信息。通常,这些信息应在应用...

Global site tag (gtag.js) - Google Analytics