Java Spring SFTP:无法重命名。正在写入文件
我正在使用SpringSFTP集成来传输文件,很多时候我都遇到了这个错误。似乎两个线程正在尝试传输相同的文件,并且相互冲突 2020-08-03 08:31:55766 INF[task-scheduler-8]o.s.i.ftp.session.FTPSSession-文件已成功从以下位置传输:./abc.ext.200803Java Spring SFTP:无法重命名。正在写入文件,java,spring,spring-integration,spring-batch,spring-integration-sftp,Java,Spring,Spring Integration,Spring Batch,Spring Integration Sftp,我正在使用SpringSFTP集成来传输文件,很多时候我都遇到了这个错误。似乎两个线程正在尝试传输相同的文件,并且相互冲突 2020-08-03 08:31:55766 INF[task-scheduler-8]o.s.i.ftp.session.FTPSSession-文件已成功从以下位置传输:./abc.ext.200803 2020-08-03 08:31:55849 INF[task-scheduler-7]o.s.i.ftp.session.FTPSSession-文件已成功从以下位
2020-08-03 08:31:55849 INF[task-scheduler-7]o.s.i.ftp.session.FTPSSession-文件已成功从以下位置传输:./abc.ext.200803
2020-08-03 08:31:55850 INF[task-scheduler-7].s.i.f.i.FtpInboundFileSynchronizer-无法重命名“/local/download/abc.ext.200803”。删除后将“写入本地文件”/local/download/abc.ext.200803”。本地文件在其他进程中可能正忙。
有没有办法使两个线程不相互干扰 我正在使用以下代码-
@Bean
public SftpInboundFileSynchronizer ftpInboundFileSynchronizer() {
isFTPSessionOK();
SftpInboundFileSynchronizer fileSynchronizer = new SftpInboundFileSynchronizer(sftpSessionFactory());
fileSynchronizer.setPreserveTimestamp(true);
fileSynchronizer.setRemoteDirectory(remoteDirectory);
fileSynchronizer.setDeleteRemoteFiles(false);
fileSynchronizer.setFilter(new SFTPLastModifiedFileFilter(remoteFileFilter));
return fileSynchronizer;
}
private boolean isFTPSessionOK() {
try {
SessionFactory<LsEntry> ftpSessionFactory = sftpSessionFactory();
boolean open = ftpSessionFactory.getSession().isOpen();
LOG.info("FTPSession is good ? " + open);
return open;
} catch (Exception e) {
LOG.error("FTPSession is not good because of error : " + e);
}
return false;
}
@Bean
public SessionFactory<LsEntry> sftpSessionFactory() {
DefaultSftpSessionFactory sf = new DefaultSftpSessionFactory();
sf.setHost(server);
sf.setPort(port);
sf.setUser(username);
sf.setPassword(password);
sf.setAllowUnknownKeys(true);
return new CachingSessionFactory<LsEntry>(sf);
}
@Bean
@InboundChannelAdapter(channel = "sftpChannel", poller = @Poller(fixedDelay = "${${project.name}.ftp.poller.delay:600000}", maxMessagesPerPoll = "1"))
public MessageSource<File> ftpMessageSource() {
SftpInboundFileSynchronizingMessageSource source = new SftpInboundFileSynchronizingMessageSource(ftpInboundFileSynchronizer());
source.setLocalDirectory(new File(localFtpDirectory));
source.setAutoCreateLocalDirectory(true);
return source;
}
@Bean
@ServiceActivator(inputChannel = "sftpChannel")
public MessageHandler ftpHandler() {
return new MessageHandler() {
@Override
public void handleMessage(Message<?> message) throws MessagingException {
LOG.info("File '{}' is ready for reading after SFTP", message.getPayload());
}
};
}
@Bean
公共SftpInboundFileSynchronizer ftpInboundFileSynchronizer(){
isFTPSessionOK();
SftpInboundFileSynchronizer fileSynchronizer=新的SftpInboundFileSynchronizer(sftpSessionFactory());
setPreserveTimestamp(true);
fileSynchronizer.setRemoteDirectory(remoteDirectory);
fileSynchronizer.setDeleteRemoteFiles(false);
setFilter(新的sftfilefilter(remoteFileFilter));
返回文件同步器;
}
私有布尔值isFTPSessionOK(){
试一试{
SessionFactory ftpSessionFactory=sftpSessionFactory();
布尔打开=ftpSessionFactory.getSession().isOpen();
日志信息(“FTPSession是否良好?”+打开);
返回打开;
}捕获(例外e){
LOG.error(“FTPSession因错误而不好:+e”);
}
返回false;
}
@豆子
公共会话工厂sftpSessionFactory(){
DefaultSftpSessionFactory sf=新的DefaultSftpSessionFactory();
设置主机(服务器);
sf.设置端口(端口);
sf.setUser(用户名);
sf.setPassword(密码);
sf.SetAllowunknowkeys(真);
返回新的CachingSessionFactory(sf);
}
@豆子
@InboundChannelAdapter(channel=“sftpChannel”,poller=@poller(fixedDelay=“${project.name}.ftp.poller.delay:600000}”,maxMessagesPerPoll=“1”))
public MessageSource ftpMessageSource(){
SftpInboundFileSynchronizingMessageSource=新的SftpInboundFileSynchronizingMessageSource(ftpInboundFileSynchronizer());
setLocalDirectory(新文件(localftpddirectory));
source.setAutoCreateLocalDirectory(true);
返回源;
}
@豆子
@ServiceActivator(inputChannel=“sftpChannel”)
public MessageHandler ftpHandler(){
返回新的MessageHandler(){
@凌驾
public void handleMessage(消息消息消息)引发MessaginException{
LOG.info(“文件{}在SFTP之后准备好读取”,message.getPayload());
}
};
}
您只有此项用于筛选:
fileSynchronizer.setFilter(new SFTPLastModifiedFileFilter(remoteFileFilter));
但是,如何使用过滤器来防止后续轮询中的重复
请参阅AcceptOnceFileListFilter
。与该sftplastdifilefilter
一起,您应该使用ChainFileListFilter
有关更多信息,请参阅文档:
你好,阿尔特姆,谢谢你的专家建议。AcceptOnceFileListFilter有一个限制。如果远程文件已更新,即时间戳已更改,则我需要再次处理该文件。如果我们在@Poller中使用单线程taskExecutor,那么它不应该尝试运行多线程,您在问题中没有提到这一点。因此,请阅读更多文档。我们肯定会在那里解释一个
sftpersistentacceptoncefilelistfilter
,它的逻辑实际上是基于lastmodified
文件属性的。