使用 Spring 集成从 FTP 获取文件
Fetching file from FTP using Spring Integration
我有一个项目,我需要从远程 FTP 文件夹中获取 .csv 文件问题是这些文件很大让我们说 6-7 MB 并且投票开始读取它们,即使不是尚未完全从第三方转入,导致异常
我看到我们可以使用 LastModifiedFileListFilter 但不确定这是否是正确的解决方案。
这是我的代码示例。
@Bean
public IntegrationFlow ftpInboundFlow() {
return IntegrationFlows
.from(Ftp.inboundAdapter(ftpSessionFactory())
.preserveTimestamp(true)
.remoteDirectory("/ftp/GE/Inbound")
.patternFilter("*.csv")
.deleteRemoteFiles(true)
.localDirectory(new File("inbound"))
.temporaryFileSuffix(TEMPORARY_FILE_SUFFIX),
e -> e.id("ftpInboundAdapter")
.poller(Pollers.fixedDelay(5000))
.autoStartup(true))
.transform(e -> {
log.info("Sending CSV file " + e + " to FTP server");
return e;
})
.handle(Ftp.outboundAdapter(ftpSessionFactory())
.useTemporaryFileName(true)
.autoCreateDirectory(true)
.remoteDirectory("/ftp/GE/Inbound/history"))
.get();
}
异常:
Caused by: org.springframework.messaging.MessagingException: Failure occurred while copying '/ftp/GE/Inbound/OA_ex_PK_2020_2021.csv' from the remote to the local directory; nested exception is java.io.IOException: Failed to copy '/ftp/GE/Inbound/OA_ex_PK_2020_2021.csv'. Server replied with: 550 The process cannot access the file because it is being used by another process.
LastModifiedFileListFilter
用于本地文件系统。然而,我认为一个想法很好,并且足以为 FTP 实现类似的“最后修改”。请参阅 FtpPersistentAcceptOnceFileListFilter
以及它如何从远程实体获取 modified
选项。
这样的 FtpLastModifiedFileListFilter
必须是 ChainFileListFilter
中的第一个,您必须将其提供到您的 Ftp.inboundAdapter
中。第二个确实是你的new FtpSimplePatternFileListFilter("*.csv")
。链中的最后一个必须是 AcceptOnceFileListFilter
或其 FTP 变体:FtpPersistentAcceptOnceFileListFilter
.
FtpLastModifiedFileListFilter
的解决方案可以回馈给框架,因为您不是第一个要求类似解决方案的人。
另一种方法是通过tmp
文件改变写入逻辑。因此,在这些 tmp 文件完全写入并分别重命名之前,您看不到最终文件。
另一种解决方案是忽略该异常,事情最终会自行解决。关键是FtpPersistentAcceptOnceFileListFilter
,在内部默认使用,是一个ReversibleFileListFilter<F>, ResettableFileListFilter<F>
,所以当FtpInboundFileSynchronizer.copyFileToLocalDirectory()
发生异常时,它有这样的逻辑:
catch (RuntimeException | IOException e1) {
if (filteringOneByOne) {
resetFilterIfNecessary(file);
}
else {
rollbackFromFileToListEnd(filteredFiles, file);
}
throw e1;
}
因此,失败的文件将从过滤器存储中删除,因此它将在下一个轮询周期再次成为。
我有一个项目,我需要从远程 FTP 文件夹中获取 .csv 文件问题是这些文件很大让我们说 6-7 MB 并且投票开始读取它们,即使不是尚未完全从第三方转入,导致异常
我看到我们可以使用 LastModifiedFileListFilter 但不确定这是否是正确的解决方案。
这是我的代码示例。
@Bean
public IntegrationFlow ftpInboundFlow() {
return IntegrationFlows
.from(Ftp.inboundAdapter(ftpSessionFactory())
.preserveTimestamp(true)
.remoteDirectory("/ftp/GE/Inbound")
.patternFilter("*.csv")
.deleteRemoteFiles(true)
.localDirectory(new File("inbound"))
.temporaryFileSuffix(TEMPORARY_FILE_SUFFIX),
e -> e.id("ftpInboundAdapter")
.poller(Pollers.fixedDelay(5000))
.autoStartup(true))
.transform(e -> {
log.info("Sending CSV file " + e + " to FTP server");
return e;
})
.handle(Ftp.outboundAdapter(ftpSessionFactory())
.useTemporaryFileName(true)
.autoCreateDirectory(true)
.remoteDirectory("/ftp/GE/Inbound/history"))
.get();
}
异常:
Caused by: org.springframework.messaging.MessagingException: Failure occurred while copying '/ftp/GE/Inbound/OA_ex_PK_2020_2021.csv' from the remote to the local directory; nested exception is java.io.IOException: Failed to copy '/ftp/GE/Inbound/OA_ex_PK_2020_2021.csv'. Server replied with: 550 The process cannot access the file because it is being used by another process.
LastModifiedFileListFilter
用于本地文件系统。然而,我认为一个想法很好,并且足以为 FTP 实现类似的“最后修改”。请参阅 FtpPersistentAcceptOnceFileListFilter
以及它如何从远程实体获取 modified
选项。
这样的 FtpLastModifiedFileListFilter
必须是 ChainFileListFilter
中的第一个,您必须将其提供到您的 Ftp.inboundAdapter
中。第二个确实是你的new FtpSimplePatternFileListFilter("*.csv")
。链中的最后一个必须是 AcceptOnceFileListFilter
或其 FTP 变体:FtpPersistentAcceptOnceFileListFilter
.
FtpLastModifiedFileListFilter
的解决方案可以回馈给框架,因为您不是第一个要求类似解决方案的人。
另一种方法是通过tmp
文件改变写入逻辑。因此,在这些 tmp 文件完全写入并分别重命名之前,您看不到最终文件。
另一种解决方案是忽略该异常,事情最终会自行解决。关键是FtpPersistentAcceptOnceFileListFilter
,在内部默认使用,是一个ReversibleFileListFilter<F>, ResettableFileListFilter<F>
,所以当FtpInboundFileSynchronizer.copyFileToLocalDirectory()
发生异常时,它有这样的逻辑:
catch (RuntimeException | IOException e1) {
if (filteringOneByOne) {
resetFilterIfNecessary(file);
}
else {
rollbackFromFileToListEnd(filteredFiles, file);
}
throw e1;
}
因此,失败的文件将从过滤器存储中删除,因此它将在下一个轮询周期再次成为。