Spring Batch远程CSV文件分块读取处理方案咨询
问题描述
需求:从远程Linux服务器读取包含4万+条记录的CSV文件,要求分块读取,无需将文件下载到本地,直接将分块数据传递给处理器和写入器。
已尝试方案如下,但不确定是否真的实现了分块读取,同时了解到SftpRemoteFileTemplate,想咨询当前方向是否正确,或是否需要使用SftpRemoteFileTemplate等其他方案。
尝试的代码:
@Bean public Job readRemoteCsvFileJob(Step step1) { return jobBuilderFactory.get("readRemoteCsvFileJob") .incrementer(new RunIdIncrementer()) .flow(step1) .end() .build(); } @Bean public Step step1(ItemReader<MyItem> reader, ItemWriter<MyItem> writer) { return stepBuilderFactory.get("step1") .<MyItem, MyItem>chunk(10) .reader(reader) .writer(writer) .build(); } @Bean public FlatFileItemReader<MyItem> reader() { FlatFileItemReader<MyItem> reader = new FlatFileItemReader<>(); reader.setResource(new UrlResource("/remote-path/myfile.csv")); reader.setLineMapper(new DefaultLineMapper<MyItem>() {{ setLineTokenizer(new DelimitedLineTokenizer() {{ setNames(new String[]{"field1", "field2"}); }}); setFieldSetMapper(new BeanWrapperFieldSetMapper<MyItem>() {{ setTargetType(MyItem.class); }}); }}); return reader; }
解决方案分析
当前方案的问题
UrlResource("/remote-path/myfile.csv")无法直接访问Linux服务器上的SFTP/FTP协议文件,除非该路径是HTTP/HTTPS暴露的可访问URL。如果是SFTP场景,UrlResource根本无法正确读取资源,更谈不上分块读取。- 就算
UrlResource能正常访问文件,FlatFileItemReader结合chunk(10)确实会按每10条记录分块传递给写入器,但这个逻辑的前提是资源支持流式读取。对于SFTP这类远程文件,当前配置不具备可行性。
正确实现方向
方案一:Spring Batch + Spring Integration SFTP组件(推荐)
要实现不下载整文件、流式分块读取远程SFTP文件,可以用SftpRemoteFileTemplate配合Spring Batch的RemoteFileItemReader,这是Spring生态下的标准实现:
- 配置SFTP连接工厂:
@Bean public DefaultSftpSessionFactory sftpSessionFactory() { DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true); factory.setHost("remote-host-ip"); factory.setPort(22); factory.setUser("username"); factory.setPassword("password"); // 密钥认证方式替代密码(二选一) // factory.setPrivateKey(new ClassPathResource("private-key.pem")); // factory.setPrivateKeyPassphrase("key-passphrase"); factory.setAllowUnknownKeys(true); return factory; } @Bean public SftpRemoteFileTemplate sftpRemoteFileTemplate() { return new SftpRemoteFileTemplate(sftpSessionFactory()); }
- 配置流式远程文件读取器:
@Bean public RemoteFileItemReader<MyItem> sftpItemReader() { RemoteFileItemReader<MyItem> reader = new RemoteFileItemReader<>(); reader.setRemoteFileTemplate(sftpRemoteFileTemplate()); reader.setRemoteDirectory("/remote-path"); reader.setFilenameExpression("myfile.csv"); // 复用你原有的行映射规则 reader.setLineMapper(new DefaultLineMapper<MyItem>() {{ setLineTokenizer(new DelimitedLineTokenizer() {{ setNames(new String[]{"field1", "field2"}); }}); setFieldSetMapper(new BeanWrapperFieldSetMapper<MyItem>() {{ setTargetType(MyItem.class); }}); }}); return reader; }
- Step配置保持原有的
chunk(10)即可,此时RemoteFileItemReader会从SFTP服务器流式读取文件,每次读取10条组成数据块直接传递给写入器,不会将整个4万条记录或完整文件下载到本地。
方案二:HTTP暴露的远程文件场景
如果远程文件是通过HTTP服务(如Nginx静态文件服务)暴露的,可将UrlResource改为完整HTTP URL(如new UrlResource("http://remote-host/myfile.csv")),此时FlatFileItemReader会流式读取文件,结合chunk(10)配置可实现分块读取,不会一次性加载所有记录到内存。但该方案仅适用于HTTP可访问的文件,不适用于SFTP/FTP协议的Linux服务器文件。
总结
- 当前方案方向不正确,
UrlResource无法处理SFTP远程文件,必须使用专门的远程文件读取组件。 - 若为SFTP协议的远程文件,优先使用
SftpRemoteFileTemplate配合RemoteFileItemReader,完全符合你流式分块、不下载本地的需求。
内容的提问来源于stack exchange,提问作者Shabarinath Volam
相关产品推荐
相关产品推荐

