相关文章推荐
深情的可乐  ·  Android ...·  4 周前    · 
才高八斗的茶叶  ·  android ...·  4 周前    · 
不要命的汉堡包  ·  WebView全面解析 ·  2 周前    · 
阳刚的硬盘  ·  Android TabLayout ...·  2 周前    · 
霸气的铅笔  ·  混合服务的新增功能·  9 月前    · 

Amazon Simple Storage Service (Amazon S3) 是一种对象存储服务,提供行业领先的可扩展性、数据可用性、安全性和性能。

Amazon S3 提供了一个简单 Web 服务接口,可用于随时在 Web 上的任何位置存储和检索任何数量的数据。此服务让所有开发人员都能访问同一个具备高扩展性、可靠性、安全性和快速价廉的数据存储基础设施。

本文分别介绍一次上传整个文件、将大文件分为几段上传以及重启后续传文件的内容。

1.上传文件

当上传的文件不是太大时,可以采用一次上传整个文件的方式上传,即使失败了,重新开始上传也不会太浪费时间。

先上代码:

String fileName = "filePath/fileName.png";
Region region = Region.getRegion(regionStr);
AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
AmazonS3 s3 = new AmazonS3Client(credentials, region);
try {
    PutObjectRequest request = new PutObjectRequest(bucketName, key, new File(fileName));
    ObjectMetadata metadata = new ObjectMetadata();
    metadata.setContentType("plain/text");
    metadata.addUserMetadata("x-amz-meta-title", "someTitle");
    request.setMetadata(metadata);
    PutObjectResult result = s3.putObject(request);
    Log.i("S3upload", "result: " + result);
}catch (Exception e){
    Log.i("S3upload", "S3 error :" + e);

使用S3上传首先要有region(AWS 区域),accessKey,secretKey,bucketName(文件将要上载到的现有存储桶的名称),这些数据都是AWS会提供。

代码中PutObjectRequest request = new PutObjectRequest(bucketName, key, new File(fileName));

这一句中的参数key为文件所要在存储桶中显示上传的文件路径以及文件名(举例:folder1/folder2/fileName.txt)

最后这个result,如果是整个文件上传,感觉并没有什么用,因为如果上传失败,会抛出错误,成功result里面也没有成功失败的参数,所以感觉没有用到这个result。

2.分段上传

上传文件时,有时候需要上传大文件,但是当网络不好、或者断网时,容易导致之前上传的内容失败,功亏一篑。这时就可以使用分段上传。重启续传是在分段上传的基础上完成的。首先先介绍分段上传。

分段上传就是将文件分为几部分分开上传,哪一部分上传失败就重传这部分内容,最后所有部分上传完成,再合在一起。

也是先上代码:

File file = new File(filePath);
long contentLength = file.length();
long partSize = 5 * 1024 * 1024;
long filePosition = 0;
int part = 1;
AWSCredentials credentials = new BasicSessionCredentials(mAccessKey, mSecretKey, mSessionToken);
Region region = Region.getRegion(mRegion);
AmazonS3 s3 = new AmazonS3Client(credentials, region);
InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(mBucketName, key);
InitiateMultipartUploadResult initResponse = s3.initiateMultipartUpload(initRequest);
for (; filePosition < contentLength; ) {
    if (filePosition > contentLength || filePosition == contentLength) {
        break;
    partSize = Math.min(partSize, (contentLength - filePosition));
    Log.i(TAG, "[S3UploadFile][S3Part]part upload : " + partSize);
    UploadPartRequest uploadRequest = new UploadPartRequest().withBucketName(mBucketName)
            .withKey(key).withUploadId(initResponse.getUploadId()).withPartNumber(part)
            .withFileOffset(filePosition).withFile(file).withPartSize(partSize);
    uploadRequest.setGeneralProgressListener(new ProgressListener() {
        @Override
        public void progressChanged(ProgressEvent progressEvent) {
            if (progressEvent.getEventCode() == ProgressEvent.PART_COMPLETED_EVENT_CODE) {
            if (progressEvent.getEventCode() == ProgressEvent.PART_FAILED_EVENT_CODE) {
    try {
        UploadPartResult uploadResult = s3.uploadPart(uploadRequest);
        mPartETags.add(uploadResult.getPartETag());
        part ++;
        filePosition += partSize;
        Log.i(TAG, "[S3UploadFile][S3Part]result ETag: " + uploadResult.getETag()
                + ", PartNumber:" + uploadResult.getPartNumber());
    } catch (Exception e) {
        Log.i(TAG, "[S3UploadFile][S3Part]S3 part error :" + e);
CompleteMultipartUploadRequest compRequest = new CompleteMultipartUploadRequest(mBucketName, key,
        initResponse.getUploadId(), mPartETags);
s3.completeMultipartUpload(compRequest);

分段上传分为几步:

1.初始化AmazonS3,并传入InitiateMultipartUploadRequest对象,获得InitiateMultipartUploadResult对象。

2.开始循环上传每个分段,首先计算出当前上传分段的大小(partSize),然后初始化UploadPartRequest,最后上传分段(s3.uploadPart)。

3.循环结束后,根据每个分段上传完成后的ETag,合并所有分段为一个文件(s3.completeMultipartUpload)

需要注意的是,分段上传中文件的每个分段(不包括最后一个分段)最小为5M(也就是代码中partSize),如果partSize小于5M,每个分段上传都可以成功,但是到最后合并每个分段时(completeMultipartUpload),会报错,会提示你分段的大小不合格。

最开始的时候初始化,使用的参数与整个文件直接上传的参数差不多。

然后开始循环上传,根据partSize与剩余没有上传的部分进行比较,得出这一分段需要上传的大小。将这一分段的信息设置到UploadPartRequest,设置的信息分别为bucketName(文件将要上载到的现有存储桶的名称)、key(在存储桶中显示上传的文件路径以及文件名)、uploadId(文件上传的id)、partNumber(这个分段是第几段)、fileOffset(从文件的哪个字节开始上传)、file、partSize(这个分段的大小),设置这些信息后,就可以开始上传分段了。

如果您想要知道这个分段上传是否成功,可以注册监听(setGeneralProgressListener),根据返回的eventCode可以知道是否上传成功,ProgressEvent.PART_COMPLETED_EVENT_CODE为上传成功,这里可以做成上传成功后,再上传后面的部分,ProgressEvent.PART_FAILED_EVENT_CODE为上传失败,这里可以做成上传失败,part与filePosition就不加,再继续上传失败的部分。(注意UploadPartResult获取会比ProgressListener的成功失败快一些,所以这里需要一下特殊的判断条件来卡住后面的上传)

UploadPartRequest设置完毕后,使用s3的uploadPart方法将Request上传,得到UploadPartResult,这里要从result里面获取ETag信息出来,方便后续合并分段时使用。

最后所有的分段上传完毕,初始化CompleteMultipartUploadRequest对象,这里需要uploadId,以及每个分段上传的ETag,使用s3.completeMultipartUpload合并分段。

3.重启续传

重启续传需要在上一节分段上传的基础上完成,在每完成一段的上传时,将上传的信息保存到本地存储,重启后,读取文件中的信息,续传。

想要重启后,继续上传之前没有上传完的文件,首先要保证你上传使用信息一致,才能继续传,使用信息不一致,可能会重新开始另一个上传。

来一步步看上传需要什么信息:

AWSCredentials credentials = new BasicSessionCredentials(mAccessKey, mSecretKey, mSessionToken);
Region region = Region.getRegion(mRegion);
AmazonS3 s3 = new AmazonS3Client(credentials, region);
InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(mBucketName, key);
InitiateMultipartUploadResult initResponse = s3.initiateMultipartUpload(initRequest);

初始化各种使用的类时,需要region,accessKey,secretKey,bucketName,key,sessionToken,其中sessionToken因为有过期的可能,可以与重启前不一致,其他信息保持一致

UploadPartRequest uploadRequest = new UploadPartRequest().withBucketName(mBucketName)
        .withKey(key).withUploadId(initResponse.getUploadId()).withPartNumber(part)
        .withFileOffset(filePosition).withFile(file).withPartSize(partSize);

构建UploadPartRequest的时候,需要bucketName,key,uploadId,partNumber,fileOffset,file,partSize,为了能够续传,必须要保持bucketName,key,uploadId一致,partNumber以及fileOffset要能够接得上之前已经上传的分段。

CompleteMultipartUploadRequest compRequest = new CompleteMultipartUploadRequest(mBucketName, key,
        initResponse.getUploadId(), mPartETags);
s3.completeMultipartUpload(compRequest);

最后从分段上传最后合并每段所需要的参数中,可以看到需要bucketName、key、uploadId以及ETags。

所以想要重启后续传之前的文件以及能够将重启前上传的分段合进去,就需要保存region,accessKey,secretKey,bucketName,key,uploadId,partNumber,fileOffset,ETags这些数据

(1) region,accessKey,secretKey,bucketName,key可以在一开始的时候就保存下来

(2) uploadId需要在构建InitiateMultipartUploadResult后,取出来保存。这里需要注意一下,新开的上传的uploadId是从InitiateMultipartUploadResult中取出来的,所以在构建了InitiateMultipartUploadResult类后,可以使用setUploadId将其中的uploadId修改了

InitiateMultipartUploadResult initResponse = s3.initiateMultipartUpload(initRequest);
initResponse.setUploadId(mUploadId);

(3) partNumber,fileOffset,ETags这些数据需要在确定上传成功后,将其保存起来,所以这时就必须要setGeneralProgressListener来监听分段是否上传成功,成功则保存信息,失败则继续传这一分段

贴一段例子:

public void upload(AmazonS3 s3, String filePath, String key, int part, long filePosition){
    ​File file = new File(filePath);
    long contentLength = file.length();
    long partSize = 5 * 1024 * 1024;
    InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(mBucketName, key);
    InitiateMultipartUploadResult initResponse = s3.initiateMultipartUpload(initRequest);
    //查看是否有uploadId,表示是续传
    if (mUploadId.length() > 0) {
        initResponse.setUploadId(mUploadId);
    } else {
        mUploadId = initResponse.getUploadId();
        //保存uplodId
    for (; filePosition < contentLength; ) {
        if (!mIsPartComplete) {
            continue;
        mIsPartComplete = false;
        if (mIsNeedAdd) {
            part++;
            filePosition += partSize;
            mIsNeedAdd = false;
            //保存partNumber,fileOffset,ETags
        if (filePosition > contentLength || filePosition == contentLength) {
            break;
        partSize = Math.min(partSize, (contentLength - filePosition));
        UploadPartRequest uploadRequest = new UploadPartRequest().withBucketName(mBucketName)
                .withKey(key).withUploadId(initResponse.getUploadId()).withPartNumber(part)
                .withFileOffset(filePosition).withFile(file).withPartSize(partSize);
        uploadRequest.setGeneralProgressListener(new ProgressListener() {
            @Override
            public void progressChanged(ProgressEvent progressEvent) {
                if (progressEvent.getEventCode() == ProgressEvent.PART_COMPLETED_EVENT_CODE) {
                    //成功上传,设置上传完成且传下一段的标志
                    mIsNeedAdd = true;
                    mIsPartComplete = true;
                if (progressEvent.getEventCode() == ProgressEvent.PART_FAILED_EVENT_CODE) {
                    //失败上传,设置上传完成但是失败
                    mIsPartComplete = true;
        // Upload the part and add the response's ETag to our list.
        try {
            UploadPartResult uploadResult = s3.uploadPart(uploadRequest);
            mPartETags.add(uploadResult.getPartETag());
            Log.i(TAG, "[S3UploadFile][S3Part]result ETag: " + uploadResult.getETag()
                    + ", PartNumber:" + uploadResult.getPartNumber());
        } catch (Exception e) {
    CompleteMultipartUploadRequest compRequest = new CompleteMultipartUploadRequest(mBucketName, key,
            initResponse.getUploadId(), mPartETags);
    s3.completeMultipartUpload(compRequest);

很多数据都是在程序运行时,从保存文件中取出来的,这里就不介绍怎么设置的这些数据了。

另,在使用S3上传时,并且已经在执行uploadPart时,一定要保证你上传的文件存在,如果在上传时,上传文件不存在了,那么会导致崩溃,这是try catch抓不住的错误,因为S3没有抛出,所以如果你的文件比如在SD卡上,SD卡又可能被人为的取掉,那么可以在上传前,将文件复制到人为不可以动到(除非root)文件夹下。

上传文件时,有时候需要上传大文件,但是当网络不好、或者断网时,容易导致之前上传的内容失败,功亏一篑。这时就可以使用分段上传。分段上传就是将文件分为几部分分开上传,哪一部分上传失败就重传这部分内容,最后所有部分上传完成,再合在一起。...
OSS分片上传文件 OSS提供的分片上传(Multipart Upload)功能,将要上传的较大文件(Object)分成多个数据块(Part)来分别上传上传完成后再调用CompleteMultipartUpload接口将这些Part组合成一个Object来达到断点续传的效果。 分片上传流程 分片上传(Multipart Upload)分为以下三个步骤: 初始化一个分片上传事件。 调用InitiateMultipartUploadRequest方法返回OSS创建的全局唯一的uploadId。 上传分片。
文章目录1.获取Pool ID2.上传失败3.网络代理问题4.代码 从官网下载aws 的unity插件,,可进行数据上传、下载等操作,文末代码在原代码基础上做了简单修改(主要用修改PostObject)。操作过程中主要存在以下几个问题: 1.获取Pool ID 其他参数比较容易获取,Pool ID则有有点隐藏:通过服务-Cognito-管理/新建用户池,可以新建或者获取Pool ID 2.上传失...
Amazon Simple Storage Service (Amazon S3) 是一种对象存储服务,提供行业领先的可扩展性、数据可用性、安全性和性能。 Amazon S3 提供了一个简单 Web 服务接口,可用于随时在 Web 上的任何位置存储和检索任何数量的数据。此服务让所有开发人员都能访问同一个具备高扩展性、可靠性、安全性和快速价廉的数据存储基础设施。 本文分别介绍一次上传整个文件和将大文件分为几段上传的内容。 二、上传文件 当上传的文件不是太大时,可以采用一次上传整个文件的方式上传,即使
上传流,只需在构造MultiPartUpload时传递流即可。 然后,上传将侦听流,并根据传入的数据流创建部分。 当零件达到最小零件尺寸时,它将尝试将其上传S3。 // Create a Knox client first var client = knox . createClient ( { ... } )
AmazonS3 android sdk接入 前段时间接了iOS的AmazonS3,用于上传及访问大文件和图片。过程比较坎坷,Android总的来说顺利很多,不过也碰到一些问题,在此记录一下 官方的示例代码 示例代码挺好的,不过不是太符合我的要求,我们服务端给的AWS凭证是动态的,每2小时更新一次。看官方的教程好像是写死在配置里的。 而且我也没找到符合我需求的示例代码。 集成方式和官网描述一样,不嫌我废话的话,我就贴一下吧。 dependencies { def aws_version = "2
FSW...: 大佬,我这边是流的形式, UploadPartRequest uploadRequest = new UploadPartRequest().withBucketName(mBucketName) .withKey(key).withUploadId(initResponse.getUploadId()).withPartNumber(part) .withFileOffset(filePosition).withFile(file).withPartSize(partSize); withFile(file)这个传参怎么传啊 Profile Owner使用总结 小智天下无敌: 作者大大我有疑惑可以劳烦解答吗 怎么判断设备是否已具有工作资料且工作资料受本应用管理 如果已知本应用是profileowner,怎么判断是哪个用户的profileowner Amazon S3上传、分段上传、重启续传介绍(Android) 称霸幼儿园: 我是为了解决大文件续传才这样做的,因为设备随时都可能关机,做这个是为了记录大文件上传的进度,方便下次开机继续上传。 Amazon S3上传、分段上传、重启续传介绍(Android) zym_123456: 大佬,弱弱地问一下,你这样循环顺序分片上传,和单文件上传有区别么?感觉好像效果一样的啊?没有达到多线程分片上传的效果。 Amazon S3上传、分段上传、重启续传介绍(Android) 称霸幼儿园: 没有遇到过,你确定一下你上传的文件是否完整上传了