Java中如何通过SFTP获取目录下最新文件?
问题根源分析
你遇到的核心问题是错误地用本地File类来获取远程SFTP文件的修改时间。当你通过new File(entry.getFilename())创建本地File对象时,这个对象对应的是本地文件系统里的文件(如果本地没有同名文件,它的属性都是默认值),完全和远程SFTP服务器上的文件无关。所以你调用file.lastModified()拿到的根本不是远程文件的真实修改时间,这就导致新增远程文件后,代码没法正确判断哪个是最新的。
正确解决方案
要解决这个问题,你得直接从JSch的LsEntry对象里获取远程文件的属性——LsEntry的getAttrs()方法能拿到远程文件的详细属性,其中getMTime()会返回远程文件的修改时间(以秒为单位的Unix时间戳),这才是我们需要用来判断最新文件的依据。
修正后的代码示例
方式1:遍历筛选最新文件
// 存储远程文件名和对应的修改时间(毫秒级) List<Map.Entry<String, Long>> remoteFileList = new ArrayList<>(); Vector<LsEntry> files = sftpChannel.ls(filePath + "*.csv"); for (LsEntry entry : files) { String filename = entry.getFilename(); // 过滤掉目录自身和上级目录的标识 if (!filename.equals(".") && !filename.equals("..")) { // 把秒级时间戳转成Java常用的毫秒级 long remoteModifyTime = entry.getAttrs().getMTime() * 1000; remoteFileList.add(new AbstractMap.SimpleEntry<>(filename, remoteModifyTime)); } } System.out.println("有效文件数量:" + remoteFileList.size()); long latestModifyTime = Long.MIN_VALUE; String latestFileName = null; for (Map.Entry<String, Long> fileEntry : remoteFileList) { if (fileEntry.getValue() > latestModifyTime) { latestFileName = fileEntry.getKey(); latestModifyTime = fileEntry.getValue(); } } // 输出或使用最新文件 System.out.println("最新文件:" + latestFileName);
方式2:排序获取最新文件
如果你习惯用排序的方式筛选,也可以基于远程文件的修改时间来排序:
Vector<LsEntry> files = sftpChannel.ls(filePath + "*.csv"); // 先过滤掉无效的目录标识 List<LsEntry> validEntries = new ArrayList<>(); for (LsEntry entry : files) { String filename = entry.getFilename(); if (!filename.equals(".") && !filename.equals("..")) { validEntries.add(entry); } } if (!validEntries.isEmpty()) { // 按远程文件修改时间倒序排序,最新的排在最前面 validEntries.sort((entry1, entry2) -> { long time1 = entry1.getAttrs().getMTime(); long time2 = entry2.getAttrs().getMTime(); return Long.compare(time2, time1); // 倒序排序 }); LsEntry latestEntry = validEntries.get(0); System.out.println("最新文件:" + latestEntry.getFilename() + ",修改时间戳(秒):" + latestEntry.getAttrs().getMTime()); }
关键注意事项
- 绝对不要用本地
File类处理远程SFTP文件的属性,两者属于完全不同的文件系统,属性没有任何关联。 - JSch的
getMTime()返回的是秒级时间戳,需要乘以1000转换成Java通用的毫秒级时间戳(如果需要和本地时间做对比的话)。 - 无需担心SFTP服务器和本地的时区差异,因为时间戳是基于UTC的,直接比较数值大小就能判断先后顺序。
内容的提问来源于stack exchange,提问作者varsha




