如何用Spring Boot高效通过SFTP合并远程大文件(无需本地下载)?
SFTP服务器端文件合并的Spring Boot高效实现方案
要实现无需全量下载文件的SFTP文件合并,核心思路是要么让服务器本地执行合并操作(零网络传输),要么通过流转发仅传输文件片段(不缓存完整文件),以下是两种可行方案:
方案一:通过SSH执行服务器端Shell命令(最优)
直接在SFTP服务器上执行cat命令完成文件合并,全程无需传输文件内容,是效率最高的方式。
实现步骤
- 引入依赖:使用JSch库建立SSH连接(Spring SFTP底层也依赖该库)
<dependency> <groupId>com.jcraft</groupId> <artifactId>jsch</artifactId> <version>0.1.55</version> </dependency>
- 编写合并服务类
import com.jcraft.jsch.*; import org.springframework.stereotype.Component; import java.io.ByteArrayInputStream; import java.io.IOException; @Component public class SshSftpMergeService { public void mergeFilesOnServer(String host, int port, String username, String password, String sourceA, String sourceB, String targetC) throws JSchException, IOException, InterruptedException { JSch jsch = new JSch(); Session session = jsch.getSession(username, host, port); session.setPassword(password); // 生产环境请替换为合法的主机密钥验证逻辑,不要跳过 session.setConfig("StrictHostKeyChecking", "no"); session.connect(); // 打开Shell通道执行合并命令 Channel channel = session.openChannel("shell"); // 构造合并命令并退出Shell String command = String.format("cat %s %s > %s\nexit\n", sourceA, sourceB, targetC); channel.setInputStream(new ByteArrayInputStream(command.getBytes())); channel.setOutputStream(System.out); // 可选,用于查看命令执行输出 channel.connect(); // 等待命令执行完成 while (!channel.isClosed()) { Thread.sleep(100); } channel.disconnect(); session.disconnect(); } }
注意事项
- 确保执行命令的SFTP用户对
folder_A、folder_B有读权限,对folder_C有写权限 - 生产环境必须关闭
StrictHostKeyChecking=no,配置正确的主机密钥验证或密钥登录方式 - 如果服务器禁用了Shell通道,该方案不可用,切换到方案二
方案二:基于SFTP流转发(无本地文件缓存)
若无法执行Shell命令,可通过SFTP流直接转发文件内容,全程仅在内存中保留固定大小的缓冲区,不保存完整文件到本地。
实现步骤
- 引入依赖:使用Spring官方的SFTP集成模块
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-integration</artifactId> </dependency> <dependency> <groupId>org.springframework.integration</groupId> <artifactId>spring-integration-sftp</artifactId> </dependency>
- 配置SFTP连接
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.integration.sftp.session.DefaultSftpSessionFactory; import org.springframework.integration.sftp.session.SftpRemoteFileTemplate; @Configuration public class SftpConfig { @Bean public DefaultSftpSessionFactory sftpSessionFactory() { DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(); factory.setHost("你的SFTP主机地址"); factory.setPort(22); factory.setUser("用户名"); factory.setPassword("密码"); // 生产环境建议使用密钥登录替代密码 // factory.setPrivateKey(new File("私钥文件路径")); // factory.setPrivateKeyPassphrase("私钥密码"); factory.setAllowUnknownKeys(true); // 生产环境请关闭,配置已知主机 return factory; } @Bean public SftpRemoteFileTemplate sftpRemoteFileTemplate(DefaultSftpSessionFactory factory) { return new SftpRemoteFileTemplate(factory); } }
- 编写流合并服务类
import org.springframework.integration.sftp.session.SftpRemoteFileTemplate; import org.springframework.stereotype.Component; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @Component public class SftpStreamMergeService { private final SftpRemoteFileTemplate sftpTemplate; public SftpStreamMergeService(SftpRemoteFileTemplate sftpTemplate) { this.sftpTemplate = sftpTemplate; } public void mergeFilesViaStream(String sourceA, String sourceB, String targetC) { sftpTemplate.execute(session -> { try (OutputStream targetOut = session.write(targetC, false); InputStream inA = session.read(sourceA); InputStream inB = session.read(sourceB)) { byte[] buffer = new byte[8192]; // 8KB缓冲区,可根据网络情况调整 int bytesRead; // 写入A.txt内容 while ((bytesRead = inA.read(buffer)) != -1) { targetOut.write(buffer, 0, bytesRead); } // 追加B.txt内容 while ((bytesRead = inB.read(buffer)) != -1) { targetOut.write(buffer, 0, bytesRead); } targetOut.flush(); } catch (IOException e) { throw new RuntimeException("文件合并失败", e); } return null; }); } }
注意事项
- 该方案会传输文件内容,但仅占用少量内存缓冲区,适合大文件合并
- 确保SFTP服务器支持流读写操作(主流服务器如OpenSSH、FileZilla Server均支持)
内容的提问来源于stack exchange,提问作者Chaitanya Pandit
相关产品推荐
相关产品推荐

