如何在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
相关产品推荐
相关产品推荐

