如何在Apache Camel路由中重新读取已跳过的文件?
实现方案说明
你的需求完全可以实现,以下是具体的改造方法:
现有代码改造方案(适配你已有的路由结构)
你当前配置的noop=true+idempotent=false已经满足「跳过的文件下一轮可被重新扫描」的前提,只需要在Processor里补充逻辑即可:
- Camel读取文件时会自动将文件元信息写入Exchange头,不需要你手动构建File对象读取大小
- 大小不一致时,直接标记停止当前路由即可,不会修改原文件,下一次扫描自动重新读取
修改后代码示例:
from("file://my/directroy/path/?recursive=true&noop=true&idempotent=false&delay=5000") // delay配置扫描间隔,单位毫秒 .aggregate(constant(true), new AggregationStrategy()) .completionSize(100).completionTimeout(100) .split(body()).process(new Processor() { public void process(Exchange exchange){ // 从Header获取当前扫描到的文件路径、扫描时记录的文件大小 String filePath = exchange.getIn().getHeader("CamelFileName", String.class); Long scanFileSize = exchange.getIn().getHeader("CamelFileLength", Long.class); // 从你自己维护的大小列表中获取该文件记录的大小 Long recordedSize = yourFileSizeMap.get(filePath); // 大小不一致,直接跳过当前文件 if (recordedSize == null || !scanFileSize.equals(recordedSize)) { exchange.setProperty(Exchange.ROUTE_STOP, true); return; } // 大小一致,执行你后续的移动/处理逻辑 doYourBusinessLogic(exchange); } });
更优的预过滤方案(性能更高)
如果你不需要先聚合再判断,可以直接在File组件扫描阶段就过滤不符合条件的文件,不需要进入后续路由逻辑:
自定义一个文件过滤器实现org.apache.camel.component.file.GenericFileFilter,在过滤逻辑里判断文件大小是否和你记录的一致,只有匹配的文件才会进入路由:
public class FileSizeMatchFilter implements GenericFileFilter<File> { private Map<String, Long> yourFileSizeMap; // 你维护的文件大小记录列表 @Override public boolean accept(GenericFile<File> file) { Long recordedSize = yourFileSizeMap.get(file.getFileName()); return recordedSize != null && file.getFileLength() == recordedSize; } }
然后将过滤器注册到Camel上下文,在File组件URI中引用即可:from("file://my/directroy/path/?recursive=true&noop=true&idempotent=false&delay=5000&filter=#yourFileSizeMatchFilter")
注意事项
- 你维护的文件大小列表需要做好并发控制,避免判断时出现读写不一致的问题
- 如果文件还处于写入状态,大小会持续变化,你也可以直接用File组件自带的
readLock=changed参数,自动检测文件是否稳定,不需要自己维护大小列表,该参数会自动跳过还在写入的文件,直到文件大小不再变化才会读取。
内容的提问来源于stack exchange,提问作者Prasad
相关产品推荐
相关产品推荐

