【问题标题】:Spring SFTP : Unable to rename .writing fileSpring SFTP:无法重命名.writing文件
【发布时间】:2020-08-03 12:30:44
【问题描述】:

我正在使用 Spring SFTP 集成来传输文件,但我多次收到此错误。似乎两个线程正在尝试传输相同的文件并相互冲突

2020-08-03 08:31:55,766 INF [task-scheduler-8] o.s.i.ftp.session.FtpSession - 文件已成功传输自:./abc.ext.200803
2020-08-03 08:31:55,849 INF [task-scheduler-7] o.s.i.ftp.session.FtpSession - 文件已成功传输自:./abc.ext.200803
2020-08-03 08:31:55,850 INF [task-scheduler-7] .s.i.f.i.FtpInboundFileSynchronizer - 无法将“/local/download/abc.ext.200803.writing”重命名为本地文件“/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());
        }
    };
}

【问题讨论】:

    标签: java spring spring-integration spring-batch spring-integration-sftp


    【解决方案1】:

    您只有这个用于过滤:

    fileSynchronizer.setFilter(new SFTPLastModifiedFileFilter(remoteFileFilter));
    

    但是如果过滤器可以防止后续轮询中出现重复呢?

    AcceptOnceFileListFilter。再加上SFTPLastModifiedFileFilter,您应该使用ChainFileListFilter

    查看文档了解更多信息:

    https://docs.spring.io/spring-integration/docs/current/reference/html/sftp.html#sftp-inbound

    https://docs.spring.io/spring-integration/docs/current/reference/html/file.html#file-reading

    【讨论】:

    • 您好 Artem,感谢您的专家建议。 AcceptOnceFileListFilter 有一个限制。如果远程文件已更新,即时间戳已更改,则我需要再次处理文件。如果我们在@Poller 中使用 SingleThread taskExecutor 那么它不应该尝试运行多个线程
    • 好吧,你没有在问题中提到这一点。因此,请阅读更多文档。我们肯定会在那里解释SftpPersistentAcceptOnceFileListFilter,它的逻辑实际上是基于lastmodified 文件属性的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-31
    • 2023-03-14
    • 1970-01-01
    • 2020-04-05
    • 1970-01-01
    相关资源
    最近更新 更多