在上传大文件到OSS时,为了让用户知道上传进度和预估剩余时间,您可以利用OSS SDK提供的进度监听功能实现一个进度条来反馈实时的上传状态。
使用阿里云SDK
以下仅列举部分SDK使用PutObject接口上传时显示进度条的代码示例。关于其他上传接口显示进度条的代码示例,请参见SDK简介。
Java
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.event.ProgressEvent;
import com.aliyun.oss.event.ProgressEventType;
import com.aliyun.oss.event.ProgressListener;
import com.aliyun.oss.model.PutObjectRequest;
import java.io.File;
// 使用进度条,需要实现ProgressListener方法
public class PutObjectProgressListenerDemo implements ProgressListener {
private long bytesWritten = 0;
private long totalBytes = -1;
private boolean succeed = false;
public static void main(String[] args) throws Exception {
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 填写Bucket名称,例如examplebucket。
String bucketName = "examplebucket";
// 填写Object完整路径,完整路径中不能包含Bucket名称。例如exampledir/exampleobject.txt。
String objectName = "exampledir/exampleobject.txt";
// 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
String pathName = "D:\\localpath\\examplefile.txt";
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);
try {
// 上传文件的同时指定进度条参数。此处PutObjectProgressListenerDemo为调用类的类名,请在实际使用时替换为相应的类名。
ossClient.putObject(new PutObjectRequest(bucketName,objectName, new File(pathName)).
<PutObjectRequest>withProgressListener(new PutObjectProgressListenerDemo()));
// 下载文件的同时指定进度条参数。此处GetObjectProgressListenerDemo为调用类的类名,请在实际使用时替换为相应的类名。
// ossClient.getObject(new GetObjectRequest(bucketName,objectName).
// <GetObjectRequest>withProgressListener(new GetObjectProgressListenerDemo()));
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
public boolean isSucceed() {
return succeed;
}
// 使用进度条需要您重写回调方法,以下仅为参考示例。
@Override
public void progressChanged(ProgressEvent progressEvent) {
long bytes = progressEvent.getBytes();
ProgressEventType eventType = progressEvent.getEventType();
switch (eventType) {
case TRANSFER_STARTED_EVENT:
System.out.println("Start to upload......");
break;
case REQUEST_CONTENT_LENGTH_EVENT:
this.totalBytes = bytes;
System.out.println(this.totalBytes + " bytes in total will be uploaded to OSS");
break;
case REQUEST_BYTE_TRANSFER_EVENT:
this.bytesWritten += bytes;
if (this.totalBytes != -1) {
int percent = (int)(this.bytesWritten * 100.0 / this.totalBytes);
System.out.println(bytes + " bytes have been written at this time, upload progress: " + percent + "%(" + this.bytesWritten + "/" + this.totalBytes + ")");
} else {
System.out.println(bytes + " bytes have been written at this time, upload ratio: unknown" + "(" + this.bytesWritten + "/...)");
}
break;
case TRANSFER_COMPLETED_EVENT:
this.succeed = true;
System.out.println("Succeed to upload, " + this.bytesWritten + " bytes have been transferred in total");
break;
case TRANSFER_FAILED_EVENT:
System.out.println("Failed to upload, " + this.bytesWritten + " bytes have been transferred");
break;
default:
break;
}
}
}
Python
# -*- coding: utf-8 -*-
from __future__ import print_function
import os, sys
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider
# 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
auth = oss2.ProviderAuth(EnvironmentVariableCredentialsProvider())
# 填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
# yourBucketName填写存储空间名称。
bucket = oss2.Bucket(auth, 'https://oss-cn-hangzhou.aliyuncs.com', 'yourBucketName')
# consumed_bytes表示已上传的数据量。
# total_bytes表示待上传的总数据量。当无法确定待上传的数据长度时,total_bytes的值为None。
def percentage(consumed_bytes, total_bytes):
if total_bytes:
rate = int(100 * (float(consumed_bytes) / float(total_bytes)))
print('\r{0}% '.format(rate), end='')
sys.stdout.flush()
# progress_callback为可选参数,用于实现进度条功能。
bucket.put_object('yourObjectName', 'a'*1024*1024, progress_callback=percentage)
.NET
using System;
using System.IO;
using System.Text;
using Aliyun.OSS;
using Aliyun.OSS.Common;
namespace PutObjectProgress
{
class Program
{
static void Main(string[] args)
{
Program.PutObjectProgress();
Console.ReadKey();
}
public static void PutObjectProgress()
{
// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
var endpoint = "yourEndpoint";
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID");
var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET");
// 填写Bucket名称。
var bucketName = "yourBucketName";
// 填写不包含Bucket名称在内的Object的完整路径。
var objectName = "yourObjectName";
// 填写本地文件的完整路径。例如,本地文件examplefile.txt存储于本地D盘的localpath路径下,则此处填写为D:\\localpath\\examplefile.txt。
var localFilename = "yourLocalFilename";
// 创建OssClient实例。
var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
// 带进度条的上传。
try
{
using (var fs = File.Open(localFilename, FileMode.Open))
{
var putObjectRequest = new PutObjectRequest(bucketName, objectName, fs);
putObjectRequest.StreamTransferProgress += streamProgressCallback;
client.PutObject(putObjectRequest);
}
Console.WriteLine("Put object:{0} succeeded", objectName);
}
catch (OssException ex)
{
Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID: {2}\tHostID: {3}",
ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
}
catch (Exception ex)
{
Console.WriteLine("Failed with error info: {0}", ex.Message);
}
}
// 获取上传进度。
private static void streamProgressCallback(object sender, StreamTransferProgressArgs args)
{
System.Console.WriteLine("ProgressCallback - Progress: {0}%, TotalBytes:{1}, TransferredBytes:{2} ",
args.TransferredBytes * 100 / args.TotalBytes, args.TotalBytes, args.TransferredBytes);
}
}
}
Android
// 构造上传请求。
// 依次填写Bucket名称(例如examplebucket)、Object完整路径(例如exampledir/exampleobject.txt)和本地文件完整路径(例如/storage/emulated/0/oss/examplefile.txt)。
// Object完整路径中不能包含Bucket名称。
PutObjectRequest put = new PutObjectRequest("examplebucket", "exampledir/exampleobject.txt", "/storage/emulated/0/oss/examplefile.txt");
// 设置进度回调函数打印进度条。
put.setProgressCallback(new OSSProgressCallback<PutObjectRequest>() {
@Override
public void onProgress(PutObjectRequest request, long currentSize, long totalSize) {
// currentSize表示已上传文件的大小,单位为字节。
// totalSize表示上传文件的总大小,单位为字节。
Log.d("PutObject", "currentSize: " + currentSize + " totalSize: " + totalSize);
}
});
// 异步上传。
OSSAsyncTask task = oss.asyncPutObject(put, new OSSCompletedCallback<PutObjectRequest, PutObjectResult>() {
@Override
public void onSuccess(PutObjectRequest request, PutObjectResult result) {
Log.d("PutObject", "UploadSuccess");
Log.d("ETag", result.getETag());
Log.d("RequestId", result.getRequestId());
}
@Override
public void onFailure(PutObjectRequest request, ClientException clientExcepion, ServiceException serviceException) {
// 请求异常。
if (clientExcepion != null) {
// 本地异常,如网络异常等。
clientExcepion.printStackTrace();
}
if (serviceException != null) {
// 服务异常。
Log.e("ErrorCode", serviceException.getErrorCode());
Log.e("RequestId", serviceException.getRequestId());
Log.e("HostId", serviceException.getHostId());
Log.e("RawMessage", serviceException.getRawMessage());
}
}
});
// task.cancel(); // 可以取消任务。
// task.waitUntilFinished(); // 等待任务完成。
Go
package main
import (
"fmt"
"os"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
)
// 定义进度条监听器。
type OssProgressListener struct {
}
// 定义进度变更事件处理函数。
func (listener *OssProgressListener) ProgressChanged(event *oss.ProgressEvent) {
switch event.EventType {
case oss.TransferStartedEvent:
fmt.Printf("Transfer Started, ConsumedBytes: %d, TotalBytes %d.\n",
event.ConsumedBytes, event.TotalBytes)
case oss.TransferDataEvent:
fmt.Printf("\rTransfer Data, ConsumedBytes: %d, TotalBytes %d, %d%%.",
event.ConsumedBytes, event.TotalBytes, event.ConsumedBytes*100/event.TotalBytes)
case oss.TransferCompletedEvent:
fmt.Printf("\nTransfer Completed, ConsumedBytes: %d, TotalBytes %d.\n",
event.ConsumedBytes, event.TotalBytes)
case oss.TransferFailedEvent:
fmt.Printf("\nTransfer Failed, ConsumedBytes: %d, TotalBytes %d.\n",
event.ConsumedBytes, event.TotalBytes)
default:
}
}
func main() {
/// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
provider, err := oss.NewEnvironmentVariableCredentialsProvider()
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
// 创建OSSClient实例。
// yourEndpoint填写Bucket对应的Endpoint,以华东1(杭州)为例,填写为https://oss-cn-hangzhou.aliyuncs.com。其它Region请按实际情况填写。
client, err := oss.New("yourEndpoint", "", "", oss.SetCredentialsProvider(&provider))
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
// yourBucketName填写存储空间名称。
bucketName := "yourBucketName"
// yourObjectName填写不包含Bucket名称在内的Object的完整路径。
objectName := "yourObjectName"
// yourLocalFile填写本地文件的完整路径。
localFile := "yourLocalFile"
bucket, err := client.Bucket(bucketName)
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
// 带进度条的上传。
err = bucket.PutObjectFromFile(objectName, localFile, oss.Progress(&OssProgressListener{}))
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
}
iOS
OSSPutObjectRequest * put = [OSSPutObjectRequest new];
// 填写Bucket名称,例如examplebucket。
put.bucketName = @"examplebucket";
// 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
put.objectKey = @"exampledir/exampleobject.txt";
// 填写本地文件的完整路径。
// 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。
put.uploadingFileURL = [NSURL fileURLWithPath:@"filePath"];
// 设置进度回调函数打印进度条。
put.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {
// 当前上传长度、当前已上传总长度、待上传的总长度。
NSLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);
};
OSSTask * putTask = [client putObject:put];
[putTask continueWithBlock:^id(OSSTask *task) {
if (!task.error) {
NSLog(@"upload object success!");
} else {
NSLog(@"upload object failed, error: %@" , task.error);
}
return nil;
}];
C++
#include <alibabacloud/oss/OssClient.h>
#include <fstream>
using namespace AlibabaCloud::OSS;
void ProgressCallback(size_t increment, int64_t transfered, int64_t total, void* userData)
{
// increment表示本次回调发送的数据大小。
// transfered表示已上传的数据大小。
// total表示上传文件的总大小。
std::cout << "ProgressCallback[" << userData << "] => " <<
increment <<" ," << transfered << "," << total << std::endl;
}
int main(void)
{
/* 初始化OSS账号信息。*/
/* yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。*/
std::string Endpoint = "yourEndpoint";
/* 填写Bucket名称,例如examplebucket。*/
std::string BucketName = "examplebucket";
/* 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。*/
std::string ObjectName = "exampledir/exampleobject.txt";
/* 初始化网络等资源。*/
InitializeSdk();
ClientConfiguration conf;
/* 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。*/
auto credentialsProvider = std::make_shared<EnvironmentVariableCredentialsProvider>();
OssClient client(Endpoint, credentialsProvider, conf);
/* yourLocalFilename填写本地文件完整路径。*/
std::shared_ptr<std::iostream> content = std::make_shared<std::fstream>("yourLocalFilename", std::ios::in|std::ios::binary);
PutObjectRequest request(BucketName, ObjectName, content);
TransferProgress progressCallback = { ProgressCallback , nullptr };
request.setTransferProgress(progressCallback);
/* 上传文件。*/
auto outcome = client.PutObject(request);
if (!outcome.isSuccess()) {
/* 异常处理。*/
std::cout << "PutObject fail" <<
",code:" << outcome.error().Code() <<
",message:" << outcome.error().Message() <<
",requestId:" << outcome.error().RequestId() << std::endl;
return -1;
}
/* 释放网络等资源。*/
ShutdownSdk();
return 0;
}
C
#include "oss_api.h"
#include "aos_http_io.h"
/* yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。*/
const char *endpoint = "yourEndpoint";
/* 填写Bucket名称,例如examplebucket。*/
const char *bucket_name = "examplebucket";
/* 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。*/
const char *object_name = "exampledir/exampleobject.txt";
/* 填写本地文件的完整路径。*/
const char *local_filename = "yourLocalFilename";
void init_options(oss_request_options_t *options)
{
options->config = oss_config_create(options->pool);
/* 用char*类型的字符串初始化aos_string_t类型。*/
aos_str_set(&options->config->endpoint, endpoint);
/* 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。*/
aos_str_set(&options->config->access_key_id, getenv("OSS_ACCESS_KEY_ID"));
aos_str_set(&options->config->access_key_secret, getenv("OSS_ACCESS_KEY_SECRET"));
/* 是否使用了CNAME。0表示不使用。*/
options->config->is_cname = 0;
/* 设置网络相关参数,比如超时时间等。*/
options->ctl = aos_http_controller_create(options->pool, 0);
}
void percentage(int64_t consumed_bytes, int64_t total_bytes)
{
assert(total_bytes >= consumed_bytes);
printf("%%%" APR_INT64_T_FMT "\n", consumed_bytes * 100 / total_bytes);
}
int main(int argc, char *argv[])
{
/* 在程序入口调用aos_http_io_initialize方法来初始化网络、内存等全局资源。*/
if (aos_http_io_initialize(NULL, 0) != AOSE_OK) {
exit(1);
}
/* 用于内存管理的内存池(pool),等价于apr_pool_t。其实现代码在apr库中。*/
aos_pool_t *pool;
/* 重新创建一个内存池,第二个参数是NULL,表示没有继承其它内存池。*/
aos_pool_create(&pool, NULL);
/* 创建并初始化options,该参数包括endpoint、access_key_id、acces_key_secret、is_cname、curl等全局配置信息。*/
oss_request_options_t *oss_client_options;
/* 在内存池中分配内存给options。*/
oss_client_options = oss_request_options_create(pool);
/* 初始化Client的选项oss_client_options。*/
init_options(oss_client_options);
/* 初始化参数。*/
aos_string_t bucket;
aos_string_t object;
aos_string_t file;
aos_list_t resp_body;
aos_table_t *resp_headers = NULL;
aos_status_t *resp_status = NULL;
aos_str_set(&bucket, bucket_name);
aos_str_set(&object, object_name);
aos_str_set(&file, local_filename);
/* 带进度条的上传。*/
resp_status = oss_do_put_object_from_file(oss_client_options, &bucket, &object, &file, NULL, NULL, percentage, &resp_headers, &resp_body);
if (aos_status_is_ok(resp_status)) {
printf("put object from file succeeded\n");
} else {
printf("put object from file failed\n");
}
/* 释放内存池,相当于释放了请求过程中各资源分配的内存。*/
aos_pool_destroy(pool);
/* 释放之前分配的全局资源。*/
aos_http_io_deinitialize();
return 0;
}