前面分享了oss c sdk使用CURL提供的Callback实现数据上传,接下来一起看一下oss c sdk使用CURL提供的Callback实现数据下载。
下载数据常见的方式有两种:下载数据到memory、下载数据到文件。大家也可以参考oss c sdk使用CURL提供的Callback方式根据自己的需求自定义下载回调函数。首先,我们一起熟悉oss c sdk中使用的一些数据结构:
struct aos_http_response_s {
int status;
aos_table_t *headers;
aos_list_t body;
int64_t body_len;
char *file_path;
aos_file_buf_t* file_buf;
int64_t content_length;
aos_pool_t *pool;
void *user_data;
aos_write_http_body_pt write_body;
aos_http_body_type_e type;
};
typedef enum {
BODY_IN_MEMORY = 0,
BODY_IN_FILE,
BODY_IN_CALLBACK
}
aos_http_body_type_e
;
typedef int (*aos_write_http_body_pt)(aos_http_response_t *resp, const char *buffer, int len);
看完上面的数据结构,如果前面有了解过oss c sdk使用CURL提供的Callback上传数据的过程,那么对上面的数据结构就不会陌生了。接下来我们结合具体的数据下载方式详细说明:
(1)从OSS下载数据到本地文件中
oss c sdk提供了oss_get_object_to_file接口用于将OSS上的数据下载到本地文件中。大家可以看一下这个函数的实现,我们重点看一下这个函数中
oss_init_read_response_body_to_file函数的实现:
int
oss_init_read_response_body_to_file(aos_pool_t *p, const aos_string_t *filename, aos_http_response_t *resp)
{
int res = AOSE_OK;
aos_file_buf_t *fb = aos_create_file_buf(p);
res =
aos_open_file_for_write(p, filename->data, fb);
if (res != AOSE_OK) {
aos_error_log("Open write file fail, filename:%s\n", filename->data);
return res;
}
resp->file_path = filename->data;
resp->file_buf = fb;
resp->write_body = aos_write_http_body_file;
resp->type = BODY_IN_FILE;
return res;
}
注意红色部分,大家可以把这部分和上面的
aos_http_response_s数据结构联系起来,相信已经想到就是在这里设置将下载数据写入本地文件。接下来我们继续跟进,分析这些设置如何和CURL提供的Callback联系上。继续贴码:
aos_http_transport_t *aos_curl_http_transport_create(aos_pool_t *p)
{
aos_func_u func;
aos_curl_http_transport_t *t;
t = (aos_curl_http_transport_t *)aos_pcalloc(p, sizeof(aos_curl_http_transport_t));
t->pool = p;
t->options = aos_default_http_transport_options;
t->cleanup = aos_fstack_create(p, 5);
func.func1 = (aos_func1_pt)aos_transport_cleanup;
aos_fstack_push(t->cleanup, t, func, 1);
t->curl = aos_request_get();
func.func1 = (aos_func1_pt)request_release;
aos_fstack_push(t->cleanup, t->curl, func, 1);
t->header_callback = aos_curl_default_header_callback;
t->read_callback = aos_curl_default_read_callback;
t->write_callback = aos_curl_default_write_callback;
return (aos_http_transport_t *)t;
}
size_t
aos_curl_default_write_callback
(char *ptr, size_t size, size_t nmemb, void *userdata){
int len; int bytes;
aos_curl_http_transport_t *t;
t = (aos_curl_http_transport_t *)(userdata);
len = size * nmemb;
if (t->controller->first_byte_time == 0) {
t->controller->first_byte_time = apr_time_now();
}
aos_curl_transport_headers_done(t);
if (t->controller->error_code != AOSE_OK) {
aos_debug_log("write callback abort");
return 0;
}
// On HTTP error, we expect to parse an HTTP error response
if (t->resp->status < 200 || t->resp->status > 299) {
bytes = aos_write_http_body_memory(t->resp, ptr, len);
assert(bytes == len);
aos_move_transport_state(t, TRANS_STATE_BODY_IN);
return bytes;
}
if (t->resp->type == BODY_IN_MEMORY && t->resp->body_len >= (int64_t)t->controller->options->max_memory_size) {
t->controller->reason = apr_psprintf(t->pool,
"receive body too big, current body size: %" APR_INT64_T_FMT ", max memory size: %" APR_INT64_T_FMT,
t->resp->body_len, t->controller->options->max_memory_size);
t->controller->error_code = AOSE_OVER_MEMORY;
aos_error_log("error reason:%s, ", t->controller->reason);
return 0;
}
if ((bytes = t->resp->write_body(t->resp, ptr, len)) < 0) {
aos_debug_log("write body failure, %d.", bytes);
t->controller->error_code = AOSE_WRITE_BODY_ERROR;
t->controller->reason = "write body failure.";
return 0;
}
aos_move_transport_state(t, TRANS_STATE_BODY_IN);
return bytes;
}
int aos_curl_transport_setup(aos_curl_http_transport_t *t) {
...
curl_easy_setopt_safe(CURLOPT_WRITEFUNCTION, t->write_callback);
...
}
好了,大家看完上面的代码应该对整个过程比较了解了,红色部分基本说明了oss c sdk如何调用CURL提供的
CURLOPT_WRITEFUNCTION了。其他一些具体细节大家可以看一下源码,有问题也欢迎大家反馈。
(2)
从OSS下载数据到memory中
oss c sdk提供了
oss_get_object_to_buffer接口将数据从OSS下载到memory中,有了上面的下载数据到文件实现,这里简单讲一下下载数据到内存的过程,注意几个地方:
aos_http_response_t *
aos_http_response_create(
aos_pool_t *p)
{
aos_http_response_t *resp;
resp = (aos_http_response_t *)aos_pcalloc(p, sizeof(aos_http_response_t));
resp->status = -1;
resp->headers = aos_table_make(p, 10);
aos_list_init(&resp->body);
resp->type = BODY_IN_MEMORY;
resp->body_len = 0;
resp->pool = p;
resp->write_body = aos_write_http_body_memory;
return resp;
}
初始化
aos_http_response_t
(也就是
aos_http_response_s的typedef
)时,默认实现将数据下载到memory,所以oss_get_object_to_buffer函数中的
oss_init_read_response_body_to_buffer也比较简单,直接使用了aos_http_response_t初始化实现部分内容:
void oss_init_read_response_body_to_buffer(aos_list_t *buffer, aos_http_response_t *resp){
aos_list_movelist(&resp->body, buffer);
}
well,上面说明了oss c sdk如何使用CURL提供的Callback实现下载数据的一些细节。通过今天和昨天的两个分享,大家对oss c sdk使用CURL进行数据上传和下载的过程有了一些了解,希望oss c sdk对大家或多或少有一些帮助,也希望有需要的用户能够根据自己的需求自定义数据上传和下载的Callback,实现一些比较有意思的功能。 对了,前面论坛中也有用户提到如何实现上传和下载数据进度条的功能,可能这两次的分享会对大家有一点启示,欢迎大家发挥自己的想象,丰富oss c sdk的功能。
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。