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

如何在Java中获取Amazon S3的上传及下载进度百分比?

我来帮你搞定这个S3上传进度百分比的问题!你原来的代码主要有两个核心问题:一是每次回调都重置了累计传输字节数,根本没法正确累加;二是没完成对不同进度事件类型的处理,导致逻辑不完整。下面给你完善后的完整实现,还附带下载进度的实现思路哦~

一、修复上传进度计算的完整代码

首先要确保你已经提前获取到了待上传文件的总大小,然后用一个外部变量来累计已传输的字节(用AtomicLong保证线程安全,避免多线程回调时的计数错误),再通过判断不同的ProgressEventType来处理上传的不同阶段:

import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.amazonaws.services.s3.model.ProgressEvent;
import com.amazonaws.services.s3.model.ProgressListener;
import com.amazonaws.services.s3.model.ProgressEventType;
import java.io.File;
import java.util.concurrent.atomic.AtomicLong;

public class S3UploadProgress {
    public static void main(String[] args) {
        String bucketName = "your-bucket-name";
        String key = "your-object-key";
        File uploadFile = new File("path/to/your/file");
        
        // 提前获取文件总大小
        long totalFileSize = uploadFile.length();
        // 用AtomicLong累计已传输字节,保证线程安全
        AtomicLong totalBytesTransferred = new AtomicLong(0);

        AmazonS3 s3Client = AmazonS3ClientBuilder.defaultClient();
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, uploadFile);
        
        putObjectRequest.setGeneralProgressListener(new ProgressListener() {
            @Override
            public void progressChanged(ProgressEvent progressEvent) {
                ProgressEventType eventType = progressEvent.getEventType();
                
                switch (eventType) {
                    case TRANSFER_STARTED_EVENT:
                        System.out.println("上传任务启动,开始传输...");
                        totalBytesTransferred.set(0); // 重置累计值
                        break;
                    case BYTE_TRANSFER_EVENT:
                        // 累加本次传输的字节数
                        long transferred = progressEvent.getBytesTransferred();
                        totalBytesTransferred.addAndGet(transferred);
                        
                        // 计算并格式化进度百分比
                        if (totalFileSize > 0) {
                            double percentage = (totalBytesTransferred.get() * 100.0) / totalFileSize;
                            System.out.printf("当前上传进度: %.2f%%%n", percentage);
                        }
                        break;
                    case TRANSFER_COMPLETED_EVENT:
                        System.out.println("上传完成!最终进度: 100.00%");
                        break;
                    case TRANSFER_FAILED_EVENT:
                        System.err.println("上传失败,请检查网络或权限!");
                        break;
                    default:
                        // 其他事件(比如暂停、恢复)可按需扩展处理
                        break;
                }
            }
        });

        // 执行上传操作
        s3Client.putObject(putObjectRequest);
    }
}
二、关键优化点说明
  • 累计变量的作用域:把totalBytesTransferred放到回调函数外部,避免每次回调都重置为0,确保能持续累加已传输的字节数
  • 事件类型处理:通过switch分支处理不同的传输阶段,让逻辑更清晰,还能在上传开始/完成/失败时给出明确提示
  • 百分比计算精度:用100.0而非100做除法,避免整数除法导致的精度丢失;用printf格式化输出,让进度显示更美观
  • 线程安全:使用AtomicLong而非普通long,防止多线程环境下的计数错误(AWS SDK的进度回调可能在后台线程触发)
三、下载进度的实现逻辑

下载进度的实现思路和上传完全一致,只需要把PutObjectRequest换成GetObjectRequest,总大小从ObjectMetadata中获取:

import com.amazonaws.services.s3.model.GetObjectRequest;
import com.amazonaws.services.s3.model.ObjectMetadata;

// 省略重复的导入和客户端初始化代码
public class S3DownloadProgress {
    public static void main(String[] args) {
        String bucketName = "your-bucket-name";
        String key = "your-object-key";
        File saveFile = new File("path/to/save/file");
        
        AmazonS3 s3Client = AmazonS3ClientBuilder.defaultClient();
        // 获取待下载文件的总大小
        ObjectMetadata metadata = s3Client.getObjectMetadata(bucketName, key);
        long totalFileSize = metadata.getContentLength();
        AtomicLong totalBytesTransferred = new AtomicLong(0);

        GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, key);
        getObjectRequest.setGeneralProgressListener(new ProgressListener() {
            @Override
            public void progressChanged(ProgressEvent progressEvent) {
                ProgressEventType eventType = progressEvent.getEventType();
                
                switch (eventType) {
                    case TRANSFER_STARTED_EVENT:
                        System.out.println("下载任务启动,开始传输...");
                        totalBytesTransferred.set(0);
                        break;
                    case BYTE_TRANSFER_EVENT:
                        long transferred = progressEvent.getBytesTransferred();
                        totalBytesTransferred.addAndGet(transferred);
                        
                        if (totalFileSize > 0) {
                            double percentage = (totalBytesTransferred.get() * 100.0) / totalFileSize;
                            System.out.printf("当前下载进度: %.2f%%%n", percentage);
                        }
                        break;
                    case TRANSFER_COMPLETED_EVENT:
                        System.out.println("下载完成!最终进度: 100.00%");
                        break;
                    case TRANSFER_FAILED_EVENT:
                        System.err.println("下载失败,请检查网络或权限!");
                        break;
                    default:
                        break;
                }
            }
        });

        // 执行下载操作
        s3Client.getObject(getObjectRequest, saveFile);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:27:29