You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Java将文件从SFTP服务器直接复制至Amazon S3存储桶指定路径

嘿,这个需求我之前在项目里实战过好多次,直接流式传输确实能避免本地磁盘占用,尤其是处理大文件的时候优势特别明显。下面我给你一步步拆解实现方案和代码:

核心思路

核心逻辑其实很简单——直接从SFTP服务器获取文件的输入流,然后把这个流直接传给AWS S3的上传API,全程不需要把文件写到本地磁盘。Java的IO流机制刚好能支持这种“管道式”的传输,既节省空间又提升效率。

所需依赖

你需要引入两个核心库:JSch(用来连接SFTP服务器)和AWS SDK for S3(用来操作S3存储桶)。如果用Maven的话,直接在pom.xml里加这些依赖:

<!-- JSch:SFTP客户端库 -->
<dependency>
    <groupId>com.jcraft</groupId>
    <artifactId>jsch</artifactId>
    <version>0.1.55</version>
</dependency>

<!-- AWS S3 SDK v2(推荐用v2,比v1更高效) -->
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>s3</artifactId>
    <version>2.20.100</version>
</dependency>
完整代码实现

下面是整合好的代码,我加了详细注释,你可以根据自己的配置修改参数:

import com.jcraft.jsch.*;
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;

import java.io.InputStream;

public class SftpToS3Transfer {

    // -------------------------- 配置参数 --------------------------
    private static final String SFTP_HOST = "your-sftp-server.com";
    private static final int SFTP_PORT = 22; // 默认SFTP端口是22
    private static final String SFTP_USERNAME = "your-sftp-username";
    // 可选:用密码或私钥,这里示例用密码,私钥的话需要加载本地密钥文件
    private static final String SFTP_PASSWORD = "your-sftp-password";

    private static final String S3_BUCKET_NAME = "your-s3-bucket-name";
    private static final String S3_REGION = "cn-north-1"; // 替换成你的S3区域,比如us-east-1
    // -------------------------- 配置结束 --------------------------

    public static void main(String[] args) {
        // SFTP上的源文件路径
        String sftpSourcePath = "/remote/directory/your-file.pdf";
        // S3上的目标路径(即对象的Key)
        String s3TargetKey = "s3-target-folder/your-file.pdf";

        try {
            transferSftpFileToS3(sftpSourcePath, s3TargetKey);
            System.out.println("🎉 文件从SFTP到S3的传输完成!");
        } catch (JSchException | SftpException e) {
            System.err.println("❌ SFTP操作出错:" + e.getMessage());
            e.printStackTrace();
        } catch (Exception e) {
            System.err.println("❌ S3上传出错:" + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 核心传输方法:从SFTP取流直接上传到S3
     */
    private static void transferSftpFileToS3(String sftpFilePath, String s3TargetKey) throws JSchException, SftpException {
        // 1. 建立SFTP连接
        JSch jsch = new JSch();
        Session sftpSession = jsch.getSession(SFTP_USERNAME, SFTP_HOST, SFTP_PORT);
        sftpSession.setPassword(SFTP_PASSWORD);
        
        // 生产环境注意:不要关闭主机密钥检查!应该将SFTP服务器公钥加入known_hosts
        sftpSession.setConfig("StrictHostKeyChecking", "no");
        sftpSession.connect();

        ChannelSftp sftpChannel = (ChannelSftp) sftpSession.openChannel("sftp");
        sftpChannel.connect();

        // 2. 用try-with-resources自动关闭流和客户端(Java 7+支持)
        try (InputStream sftpFileStream = sftpChannel.get(sftpFilePath);
             S3Client s3Client = buildS3Client()) {

            // 3. 构造S3上传请求
            PutObjectRequest uploadRequest = PutObjectRequest.builder()
                    .bucket(S3_BUCKET_NAME)
                    .key(s3TargetKey)
                    // 可选:设置文件的Content-Type,比如"application/pdf"
                    //.contentType("application/octet-stream")
                    .build();

            // 4. 直接把SFTP的输入流传给S3,全程不落地本地
            s3Client.putObject(uploadRequest, 
                RequestBody.fromInputStream(sftpFileStream, sftpChannel.lstat(sftpFilePath).getSize()));

        } catch (Exception e) {
            throw new RuntimeException("传输过程中发生异常", e);
        } finally {
            // 手动关闭SFTP资源,确保连接释放
            if (sftpChannel != null && sftpChannel.isConnected()) {
                sftpChannel.disconnect();
            }
            if (sftpSession != null && sftpSession.isConnected()) {
                sftpSession.disconnect();
            }
        }
    }

    /**
     * 构建S3客户端(用默认凭证链,安全又方便)
     */
    private static S3Client buildS3Client() {
        return S3Client.builder()
                .region(software.amazon.awssdk.regions.Region.of(S3_REGION))
                // 默认凭证链:会自动从环境变量、IAM角色、~/.aws/credentials等地方取凭证
                .credentialsProvider(DefaultCredentialsProvider.create())
                .build();
    }
}
关键注意事项
  • SFTP主机密钥安全:生产环境绝对不要设置StrictHostKeyChecking=no!应该把SFTP服务器的公钥添加到~/.ssh/known_hosts文件中,防止中间人攻击。
  • 凭证不要硬编码:代码里的密码、密钥都是示例,生产环境一定要用环境变量、配置中心(比如Spring Cloud Config)或者AWS IAM角色(如果在EC2/EKS上运行,IAM角色是最优解,无需手动管理密钥)。
  • 大文件自动分段:AWS SDK v2会自动对大文件(默认超过100MB)进行分段上传,不需要你手动拆分流,底层会处理并发和重试,不用担心内存溢出。
  • 资源关闭:一定要用try-with-resources或者finally块关闭所有流和客户端,避免资源泄漏。
  • 异常重试:如果你的网络不稳定,可以添加重试机制,比如用Guava的Retryer或者AWS SDK自带的重试策略(默认已经有基础重试,但可以自定义)。

内容的提问来源于stack exchange,提问作者sunny rajpal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:02:51