FTP下载时本地自动创建空文件及MLST类型转换异常求助
Java FTP下载:避免空文件+MLST类型转换问题解决
我来帮你搞定这两个FTP开发里的常见问题,都是踩过坑才知道的细节~
一、避免远程文件不存在时创建本地空文件
问题根源
你之前的代码之所以会生成空文件,是因为调用retrieveFile()时,本地输出流已经提前打开并创建了文件,哪怕远程文件不存在、下载失败,这个空文件也会留在本地。
解决思路:先验后下
正确的流程应该是:先检查远程文件是否存在,确认存在后再打开本地输出流执行下载。同时,为了应对下载中途失败的情况,还可以在下载失败后清理本地文件。
代码示例
import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPFile; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class FtpDownloadExample { public static void main(String[] args) { FTPClient ftpClient = new FTPClient(); String server = "your-ftp-server.com"; int port = 21; String user = "username"; String pass = "password"; String remoteFilePath = "/remote/path/your-file.txt"; String localFilePath = "./local/your-file.txt"; try { ftpClient.connect(server, port); ftpClient.login(user, pass); ftpClient.enterLocalPassiveMode(); // 被动模式,避免防火墙问题 // 1. 先检查远程文件是否存在(用mlistFile高效查询单个文件) FTPFile remoteFile = ftpClient.mlistFile(remoteFilePath); if (remoteFile == null) { System.out.println("远程文件不存在,跳过下载"); return; } // 2. 确认存在后,再打开本地输出流并执行下载 File localFile = new File(localFilePath); try (OutputStream outputStream = new FileOutputStream(localFile)) { boolean downloadSuccess = ftpClient.retrieveFile(remoteFilePath, outputStream); if (downloadSuccess) { System.out.println("文件下载成功!"); } else { // 下载失败(比如中途断开),删除本地空文件 if (localFile.exists()) { localFile.delete(); System.out.println("下载失败,已清理本地空文件"); } } } } catch (IOException e) { e.printStackTrace(); } finally { // 关闭FTP连接 try { if (ftpClient.isConnected()) { ftpClient.logout(); ftpClient.disconnect(); } } catch (IOException e) { e.printStackTrace(); } } } }
关键细节
- 用
mlistFile()替代listFiles():前者只查询单个文件的状态,比遍历整个目录高效得多; - 资源自动关闭:用
try-with-resources确保输出流自动关闭; - 失败清理:即使下载中途出错,也能删除本地残留的空文件。
二、MLST命令的类型转换问题解决
问题分析
你遇到的类型转换问题,大概率是因为手动解析MLST响应字符串,或者错误地直接转换FTPFile的属性值。MLST返回的是键值对格式的字符串(比如modify=20240520143000;create=20240520100000;...),直接强转肯定会出错。
正确做法:用FTPClient封装的API处理
Apache Commons Net的FTPClient.mlistFile()方法已经帮你解析了MLST响应,返回的FTPFile对象包含了所有可用属性,直接调用方法或遍历属性即可。
代码示例:获取文件时间属性
FTPFile remoteFile = ftpClient.mlistFile(remoteFilePath); if (remoteFile != null) { // 1. 获取最后修改时间(最可靠,几乎所有服务器都支持) long lastModifiedMillis = remoteFile.getTimestamp().getTimeInMillis(); System.out.println("最后修改时间:" + new java.util.Date(lastModifiedMillis)); // 2. 获取创建时间(注意:部分FTP服务器不支持create字段) for (String attribute : remoteFile.getAttributes()) { if (attribute.startsWith("create=")) { String createTimeStr = attribute.substring(7); // 截取"create="后面的时间字符串 // 转换为Date对象,格式通常为YYYYMMDDHHMMSS java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyyMMddHHmmss"); try { java.util.Date createDate = sdf.parse(createTimeStr); System.out.println("创建时间:" + createDate); } catch (java.text.ParseException e) { System.out.println("解析创建时间失败:" + e.getMessage()); } break; } } }
兼容性处理
如果你的FTP服务器不支持MLST命令,可以先做兼容性检查:
if (ftpClient.hasFeature("MLST")) { // 使用MLST查询 FTPFile remoteFile = ftpClient.mlistFile(remoteFilePath); // ... 处理逻辑 } else { // 降级使用传统方法,比如getModificationTime() String modifyTimeStr = ftpClient.getModificationTime(remoteFilePath); // 解析modifyTimeStr(格式通常为YYYYMMDDHHMMSS) // ... }
内容的提问来源于stack exchange,提问作者User412387
相关产品推荐
相关产品推荐

