夏令时切换后Apache FTPClient的listFiles()返回null成员问题求助
Apache FTPClient listFiles() 返回null成员(夏令时切换后异常)
问题背景
我们团队基于Apache FTPClient库(导入org.apache.commons.net.ftp.*包)实现FTP服务器指定目录的文件获取逻辑,核心调用listFiles()方法获取文件列表。根据官方文档说明,该方法会自动检测服务器返回的文件列表格式,返回对应文件信息数组;若单个文件的信息解析失败,数组中会出现null成员。
异常现象
- 夏令时切换前,
listFiles()返回的数组无null成员,业务逻辑运行正常 - 夏令时切换后,即便目标目录存在有效文件,方法返回的数组仍包含null成员
- 将目录内文件移除并重新上传后,
listFiles()恢复正常,不再返回null成员 - 初步推测:异常源于夏令时切换后旧文件的日期时间解析失败
问题根源分析
Apache FTPClient的listFiles()方法依赖解析FTP服务器返回的文件时间戳字符串生成FTPFile对象。夏令时切换后,服务器上已存在的旧文件的时间戳可能保留了切换前的时区偏移或格式,而客户端的自动解析逻辑无法适配这种变化,导致解析失败生成null;重新上传的文件会使用切换后的时区生成新的时间戳,解析逻辑可正常处理。
解决方案
1. 显式指定FTP服务器的文件列表解析器
放弃自动检测,根据FTP服务器的操作系统类型(如UNIX、Windows)手动指定解析器,避免自动检测的兼容性问题:
FTPClient ftpClient = new FTPClient(); // 完成服务器连接后设置解析器 FTPFileEntryParserFactory parserFactory = new DefaultFTPFileEntryParserFactory(); // 替换为对应服务器类型,比如"WINDOWS"或"UNIX" FTPFileEntryParser parser = parserFactory.createFileEntryParser("UNIX"); ftpClient.setFileEntryParser(parser);
2. 同步客户端与服务器时区
夏令时切换可能导致客户端与服务器时区偏移不匹配,显式设置客户端时区与服务器一致:
// 在初始化FTPClient前设置JVM时区(替换为服务器实际时区) System.setProperty("user.timezone", "Europe/London"); // 部分新版本FTPClient支持直接设置服务器时区 ftpClient.setServerTimeZoneId("Europe/London");
3. 升级Apache Commons Net版本
旧版本的FTPClient存在夏令时相关的解析bug,升级到最新稳定版(推荐3.9.0及以上),官方已修复部分时区解析的兼容性问题。
4. 自定义解析逻辑处理异常时间格式
如果上述方法无效,可自定义FTPFileEntryParser,重写解析逻辑兼容夏令时切换前后的时间格式:
public class CustomUnixParser extends UnixFTPEntryParser { private static final TimeZone SERVER_TIMEZONE = TimeZone.getTimeZone("Europe/London"); private static final SimpleDateFormat DATE_FORMAT_OLD = new SimpleDateFormat("MMM dd yyyy"); private static final SimpleDateFormat DATE_FORMAT_NEW = new SimpleDateFormat("MMM dd HH:mm"); static { DATE_FORMAT_OLD.setTimeZone(SERVER_TIMEZONE); DATE_FORMAT_NEW.setTimeZone(SERVER_TIMEZONE); } @Override protected FTPFile parseFTPEntry(String entry) { FTPFile file = super.parseFTPEntry(entry); if (file == null) { // 尝试自定义解析逻辑,提取时间部分并适配不同格式 // 此处示例仅为参考,需根据服务器实际返回格式调整 try { String[] parts = entry.split("\\s+"); String timeStr = parts[5] + " " + parts[6]; Date fileDate; try { fileDate = DATE_FORMAT_NEW.parse(timeStr); } catch (ParseException e) { fileDate = DATE_FORMAT_OLD.parse(timeStr); } // 手动构建FTPFile对象并设置时间等属性 file = new FTPFile(); file.setTimestamp(fileDate); // 补充其他属性(文件名、权限等)的解析逻辑 } catch (Exception e) { // 解析失败仍返回null,或根据业务需求处理 } } return file; } } // 使用自定义解析器 ftpClient.setFileEntryParser(new CustomUnixParser());
验证方案
应用上述任一方案后,分别测试夏令时切换前后生成的文件列表获取情况,确认listFiles()返回的数组不再包含null成员。
内容的提问来源于stack exchange,提问作者Amit Toledano
相关产品推荐
相关产品推荐

