上传文件
上传文件
在 BOS 中,用户操作的基本数据单元是 Object。Bucket 中的 Object 数量不限,但单个 Object 最大允许存储 5 TB 的数据。Object 包含 Key、Meta 和 Data。其中,Key 是 Object 的名字;Meta 是用户对该 Object 的描述,由一系列 Name-Value 对组成;Data 是 Object 的数据。
BOS Python SDK提供了丰富的文件上传接口,可以通过以下方式上传文件:
- 简单上传
- 追加上传
- 分块上传
- 断点续传上传
- 获取上传进度
Object 的命名规范如下:
- 使用 UTF-8 编码。
- 长度必须在 1~1023 字节之间。
- 首字母不能为
/,不能包含@字符,@用于图片处理接口。
本文示例默认已完成如下客户端初始化。实际使用时,请将鉴权信息和 Endpoint 替换为您的配置。
1from baidubce.auth.bce_credentials import BceCredentials
2from baidubce.bce_client_configuration import BceClientConfiguration
3from baidubce.services.bos.bos_client import BosClient
4
5access_key_id = "your-access-key-id"
6secret_access_key = "your-secret-access-key"
7endpoint = "https://bj.bcebos.com"
8
9config = BceClientConfiguration(
10 credentials=BceCredentials(access_key_id, secret_access_key),
11 endpoint=endpoint
12)
13bos_client = BosClient(config)
14
15bucket_name = "example-bucket"
16object_key = "example/object.txt"
17file_name = "/path/to/local-file.txt"
简单上传
BOS在简单上传的场景中,支持以指定文件形式、以数据流方式、以字符串方式执行Object上传,请参考如下代码:
1import os
2
3string_data = "hello bos"
4
5# 以数据流形式上传 Object。用户需要自行计算数据长度 content_length。
6content_length = os.path.getsize(file_name)
7with open(file_name, "rb") as data_stream:
8 bos_client.put_object(
9 bucket_name,
10 object_key,
11 data_stream,
12 content_length
13 )
14
15# 从字符串中上传 Object。
16bos_client.put_object_from_string(
17 bucket_name,
18 object_key,
19 string_data
20)
21
22# 从文件中上传 Object。
23bos_client.put_object_from_file(
24 bucket_name,
25 object_key,
26 file_name
27)
其中,data_stream 为流对象。不同类型的 Object 采用不同的处理方法,从字符串中上传使用字符串数据,从文件中上传使用本地文件路径,因此 BOS 提供了封装好的接口方便用户进行快速上传。
Object 以文件的形式上传到 BOS 中,put_object 相关接口均支持不超过 5 GB 的 Object 上传。在 put_object 、put_object_from_string 或者 put_object_from_file 请求处理成功后,BOS 会在 Header 中返回 Object 的 ETag 作为文件标识。
这些接口均有可选参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
content_type |
str |
否 | 上传文件或字符串的类型。 |
content_md5 |
str |
否 | 文件数据校验。设置后,BOS 会启用文件内容 MD5 校验,把您提供的 MD5 与文件的 MD5 比较,不一致会抛出错误。 |
content_length |
int |
put_object 必填 |
定义文件长度,put_object_from_string() 不包含该参数。 |
content_sha256 |
str |
否 | 用于进行文件 SHA-256 校验。 |
content_crc32 |
int |
否 | 上传 Object 的 CRC32 值(IEEE 算法)。 |
content_crc32c |
int |
否 | 上传 Object 的 CRC32C 值(Castagnoli 算法)。 |
content_crc32c_flag |
bool |
否 | 是否计算 CRC32C,仅设置为 True 时有效。 |
content_crc64ecma |
int |
否 | 上传 Object 的 CRC64 值。 |
user_metadata |
dict |
否 | 用户自定义元数据。 |
storage_class |
str |
否 | 设置文件存储类型。 |
user_headers |
dict |
否 | 用户定义 Header。 |
progress_callback |
callable |
否 | 上传进度回调函数。 |
traffic_limit |
int |
否 | 单链接限速值,单位为 bit/s。 |
cond_read_write |
dict |
否 | 条件读写字段。 |
Python SDK 中提供了计算 content_md5、content_sha256、content_crc32、content_crc32c、content_crc64ecma 的内置工具:
1import os
2from baidubce import utils
3
4content_length = os.path.getsize(file_name)
5
6# 计算 content_md5,必选 fp,可选 offset、length、buf_size。
7with open(file_name, "rb") as file_stream:
8 content_md5 = utils.get_md5_from_fp(file_stream)
9 file_stream.seek(0)
10 bos_client.put_object(
11 bucket_name,
12 object_key,
13 file_stream,
14 content_length,
15 content_md5=content_md5
16 )
17
18# 计算 content_sha256,必选 fp,可选 offset、length、buf_size。
19with open(file_name, "rb") as file_stream:
20 content_sha256 = utils.get_sha256_from_fp(file_stream)
21 file_stream.seek(0)
22 bos_client.put_object(
23 bucket_name,
24 object_key,
25 file_stream,
26 content_length,
27 content_sha256=content_sha256
28 )
29
30# 计算 content_crc32,必选 fp,可选 offset、length、buf_size。
31with open(file_name, "rb") as file_stream:
32 content_crc32 = utils.get_crc32_from_fp(file_stream)
33 file_stream.seek(0)
34 bos_client.put_object(
35 bucket_name,
36 object_key,
37 file_stream,
38 content_length,
39 content_crc32=content_crc32
40 )
41
42# 计算 content_crc32c,必选 fp,可选 offset、length、buf_size。
43with open(file_name, "rb") as file_stream:
44 content_crc32c = utils.get_crc32c_from_fp(file_stream)
45 file_stream.seek(0)
46 bos_client.put_object(
47 bucket_name,
48 object_key,
49 file_stream,
50 content_length,
51 content_crc32c=content_crc32c,
52 content_crc32c_flag=True
53 )
54
55# 计算 content_crc64ecma,必选 fp,可选 offset、length、buf_size。
56with open(file_name, "rb") as file_stream:
57 content_crc64ecma = utils.get_crc64_ecma_from_fp(file_stream)
58 file_stream.seek(0)
59 bos_client.put_object(
60 bucket_name,
61 object_key,
62 file_stream,
63 content_length,
64 content_crc64ecma=content_crc64ecma
65 )
设置文件元信息
文件元信息(Object Meta),是对用户在向 BOS 上传文件时,同时对文件进行的属性描述,主要分为两种:设置 HTTP 标准属性(HTTP Headers)和用户自定义的元信息。
设定 Object 的 HTTP Header
BOS Python SDK 本质上是调用后台的 HTTP 接口,因此用户可以在上传文件时自定义 Object 的 HTTP Header。常用的 HTTP Header 说明如下:
| 名称 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
Cache-Control |
str |
否 | 无 | 指定该 Object 被下载时网页的缓存行为。 |
Content-Encoding |
str |
否 | 无 | 表示消息主体进行了何种方式的内容编码转换。 |
Content-Disposition |
str |
否 | 无 | 指示 MIME 用户代理如何显示附加的文件,例如打开或下载,以及文件名称。 |
Expires |
str |
否 | 无 | 缓存过期时间。 |
参考代码如下:
-
从字符串中上传带有特定header的object
Python1string_data = "hello bos header" 2user_headers = { 3 "Cache-Control": "no-cache", 4 "Content-Encoding": "identity", 5 "Content-Disposition": "attachment; filename=\"example.txt\"", 6 "Expires": "Wed, 21 Oct 2030 07:28:00 GMT" 7} 8 9# 从字符串中上传带有特定 Header 的 Object。 10bos_client.put_object_from_string( 11 bucket=bucket_name, 12 key=object_key, 13 data=string_data, 14 user_headers=user_headers 15) 16 17# 从文件中上传带有特定 Header 的 Object。 18bos_client.put_object_from_file( 19 bucket=bucket_name, 20 key=object_key, 21 file_name=file_name, 22 user_headers=user_headers 23)
上传后,可通过 get_object_meta_data() 查询 Object 元信息,确认 cache_control、content_encoding、content_disposition、expires 等字段是否与上传时设置一致。
用户自定义元信息
BOS支持用户自定义元数据来对Object进行描述。如下代码所示:
1string_data = "hello bos metadata"
2
3# 用户自定义元数据。
4user_metadata = {
5 "name": "my-data"
6}
7
8# 从字符串中上传带有用户自定义 Meta 的 Object。
9bos_client.put_object_from_string(
10 bucket=bucket_name,
11 key=object_key,
12 data=string_data,
13 user_metadata=user_metadata
14)
15
16# 从文件中上传带有用户自定义 Meta 的 Object。
17bos_client.put_object_from_file(
18 bucket=bucket_name,
19 key=object_key,
20 file_name=file_name,
21 user_metadata=user_metadata
22)
提示:
- 在上面代码中,用户自定义了一个名字为
name,值为my-data的元数据。- 当用户下载此 Object 的时候,此元数据也可以一并得到。
- 一个 Object 可以有多个类似的参数,但所有的 User Meta 总大小不能超过 2 KB。
设置Object的Copy属性
BOS同时会提供 copy_object 接口用于将一个已经存在的 Object 拷贝到另外一个 Object ,拷贝过程中会对源 Object 的 Etag 或修改状态进行判断,根据判断结果决定是否执行拷贝。详细的参数解释如下:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
x-bce-copy-source-if-match |
str |
否 | 如果源 Object 的 ETag 值和用户提供的 ETag 相等,则执行拷贝操作,否则拷贝失败。 |
x-bce-copy-source-if-none-match |
str |
否 | 如果源 Object 的 ETag 和用户提供的 ETag 不相等,则执行拷贝操作,否则拷贝失败。 |
x-bce-copy-source-if-unmodified-since |
str |
否 | 如果源 Object 在指定时间之后没有被修改,则执行拷贝操作,否则拷贝失败。 |
x-bce-copy-source-if-modified-since |
str |
否 | 如果源 Object 在指定时间之后被修改了,则执行拷贝操作,否则拷贝失败。 |
对应的示例代码:
1source_bucket_name = bucket_name
2source_key = "source-object.txt"
3target_bucket_name = bucket_name
4target_key = "target-object.txt"
5
6user_metadata = {
7 "name": "my-data"
8}
9user_headers = {
10 "Content-Type": "text/plain"
11}
12copy_object_user_headers = {
13 "x-bce-copy-source-if-match": "source-object-etag"
14}
15
16bos_client.copy_object(
17 source_bucket_name=source_bucket_name,
18 source_key=source_key,
19 target_bucket_name=target_bucket_name,
20 target_key=target_key,
21 user_metadata=user_metadata,
22 user_headers=user_headers,
23 copy_object_user_headers=copy_object_user_headers
24)
上传Object时设置存储类型
BOS支持标准存储, 低频存储,冷存储和归档存储,在 bj、su、gz 还支持多 AZ 的存储类型,具体可参考多AZ存储。上传 Object 并存储为某种存储类型时通过指定 StorageClass 实现,默认为标准存储,七种存储类型对应的参数如下:
| 存储类型 | 参数 |
|---|---|
| 标准存储 | STANDARD |
| 多 AZ 标准存储 | MAZ_STANDARD |
| 低频存储 | STANDARD_IA |
| 多 AZ 低频存储 | MAZ_STANDARD_IA |
| 冷存储 | COLD |
| 多 AZ 冷存储 | MAZ_COLD |
| 归档存储 | ARCHIVE |
注意:
上传多 AZ 文件需要当前 bucket 是多 AZ 类型的。
以冷存储和归档存储为例,代码如下:
1from baidubce.services.bos import storage_class
2
3string_data = "hello bos storage class"
4
5# 从文件中上传冷存储类型的 Object。
6bos_client.put_object_from_file(
7 bucket=bucket_name,
8 key=object_key,
9 file_name=file_name,
10 storage_class=storage_class.COLD
11)
12
13# 从字符串上传冷存储类型的 Object。
14bos_client.put_object_from_string(
15 bucket=bucket_name,
16 key=object_key,
17 data=string_data,
18 storage_class=storage_class.COLD
19)
20
21# 从文件中上传归档存储类型的 Object。
22bos_client.put_object_from_file(
23 bucket=bucket_name,
24 key=object_key,
25 file_name=file_name,
26 storage_class=storage_class.ARCHIVE
27)
追加上传
上面介绍的简单上传方式,创建的 Object 都是 Normal 类型,用户不可再进行追加写,这在日志、视频监控、视频直播等数据复写较频繁的场景中使用不方便。
正因如此,百度智能云 BOS 支持 AppendObject ,即以追加写的方式上传文件。通过 AppendObject 操作创建的 Object 类型为 Appendable Object,可以对该 Object 追加数据。AppendObject 大小限制为 0~5 GB。归档存储类型不支持追加上传。
通过 AppendObject 方式上传示例代码如下:
1from baidubce import utils
2from io import BytesIO
3from baidubce.services.bos import storage_class
4
5def get_content_md5(data_bytes):
6 """计算 Content-MD5,返回 Base64 编码后的 MD5 值。"""
7 return utils.get_md5_from_fp(BytesIO(data_bytes))
8
9first_data = b"first append line\n"
10second_data = b"second append line\n"
11
12# 上传 Appendable Object。
13response = bos_client.append_object(
14 bucket_name=bucket_name,
15 key=object_key,
16 data=BytesIO(first_data),
17 content_md5=get_content_md5(first_data),
18 content_length=len(first_data)
19)
20
21# 获取下次追加写的位置。
22next_offset = response.metadata.bce_next_append_offset
23
24bos_client.append_object(
25 bucket_name=bucket_name,
26 key=object_key,
27 data=BytesIO(second_data),
28 content_md5=get_content_md5(second_data),
29 content_length=len(second_data),
30 offset=next_offset
31)
32
33# 从字符串上传 Appendable Object。
34bos_client.append_object_from_string(
35 bucket_name=bucket_name,
36 key=object_key,
37 data="third append line\n",
38 offset=next_offset,
39 storage_class=storage_class.STANDARD,
40 user_headers={"Content-Type": "text/plain"}
41)
append_object 关键参数说明如下:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
bucket_name |
str |
是 | Bucket 名称。 |
key |
str |
是 | Object 名称。 |
data |
io.BufferedReader |
是 | 待追加的数据流。 |
content_md5 |
str |
否 | 待追加数据的 MD5 校验值。 |
content_length |
int |
是 | 待追加数据长度,单位为字节。 |
offset |
int |
否 | 追加写入位置。首次创建 Appendable Object 时可不传,后续追加建议使用上一次响应中的 bce_next_append_offset。 |
storage_class |
str |
否 | 存储类型,归档存储类型不支持追加上传。 |
user_headers |
dict |
否 | 用户定义 Header。 |
progress_callback |
callable |
否 | 上传进度回调函数。 |
traffic_limit |
int |
否 | 单链接限速值,单位为 bit/s。 |
分块上传
除了通过 put_object 接口上传文件到 BOS 以外,BOS 还提供了另外一种上传模式 —— Multipart Upload。用户可以在如下的应用场景内(但不仅限于此),使用 Multipart Upload 上传模式:
- 需要支持断点上传。
- 上传超过 5 GB 大小的文件。
- 网络条件较差,和 BOS 的服务器之间的连接经常断开。
- 需要流式地上传文件。
- 上传文件之前,无法确定上传文件的大小。
下面将介绍分步实现Multipart Upload。
初始化Multipart Upload
BOS使用initiate_multipart_upload方法来初始化一个分块上传事件:
1upload_id = bos_client.initiate_multipart_upload(bucket_name, object_key).upload_id
该方法会返回 InitMultipartUploadResponse 对象,此对象中包含 upload_id 参数,用来表示此次的上传事件。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
bucket_name |
str |
是 | Bucket 名称。 |
key |
str |
是 | Object 名称。 |
storage_class |
str |
否 | 分块上传完成后 Object 的存储类型。 |
user_headers |
dict |
否 | 用户定义 Header。 |
user_metadata |
dict |
否 | 用户自定义元数据。 |
带有特定header的分块上传的初始化
1bos_client.initiate_multipart_upload(
2 bucket_name=bucket,
3 key=object_key,
4 user_headers=user_headers
5)
其中,header可设置的属性有:"Cache-Control"、"Content-Encoding"、"Content-Disposition"、"Expires",get-object和get-object-meta两个接口会返回设置的这四个header。
低频、冷存储、归档存储存储分块上传的初始化
低频存储分块上传的初始化需要指定 storage_class,请参考以下代码,冷存储和归档存储以此类推:
1from baidubce.services.bos import storage_class
2
3bos_client.initiate_multipart_upload(
4 bucket_name=bucket_name,
5 key=object_key,
6 storage_class=storage_class.STANDARD_IA
7)
上传分块
初始化完成后,进行分块上传:
1import os
2
3left_size = os.path.getsize(file_name)
4
5# offset 用于设置分块开始位置。
6offset = 0
7part_number = 1
8part_list = []
9
10while left_size > 0:
11 # 设置每块为 5 MB。
12 part_size = 5 * 1024 * 1024
13 if left_size < part_size:
14 part_size = left_size
15
16 response = bos_client.upload_part_from_file(
17 bucket_name,
18 object_key,
19 upload_id,
20 part_number,
21 part_size,
22 file_name,
23 offset
24 )
25
26 left_size -= part_size
27 offset += part_size
28 part_list.append({
29 "partNumber": part_number,
30 "eTag": response.metadata.etag
31 })
32
33 part_number += 1
注意:
offset参数以字节为单位,为分块的开始偏移位置。size参数以字节为单位,定义每个分块的大小,除最后一个 Part 以外,其他的 Part 大小都要大于 5 MB。但是 Upload Part 接口并不会立即校验上传 Part 的大小;只有当调用complete_multipart_upload()的时候才会校验。- 为了保证数据在网络传输过程中不出现错误,建议您在 Upload Part 后,使用每个分块 BOS 返回的 Content-MD5 值分别验证已上传分块数据的正确性。当所有分块数据合成一个 Object 后,不再含 MD5 值。在数据上传的过程中若是没有传入任何校验字段,SDK 会默认计算 CRC32 字段。
- Part 号码的范围是 1~10000。如果超出这个范围,BOS 将返回
InvalidArgument的错误码。- 每次上传 Part 时都要把流定位到此次上传块开头所对应的位置。
- 每次上传 Part 之后,BOS 的返回结果会包含一个
etag与块编号(partNumber),在后续完成分块上传的步骤中会用到它,因此需要将其保存起来。一般来讲这些etag和partNumber将被保存到 List 中。
upload_part_from_file 关键参数说明如下:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
bucket_name |
str |
是 | Bucket 名称。 |
key |
str |
是 | Object 名称。 |
upload_id |
str |
是 | 初始化 Multipart Upload 返回的上传事件 ID。 |
part_number |
int |
是 | 分块编号,取值范围为 1~10000。 |
size |
int |
是 | 本次上传分块大小,单位为字节。 |
file_name |
str |
是 | 本地文件路径。 |
offset |
int |
是 | 本次上传分块在文件中的开始偏移位置,单位为字节。 |
progress_callback |
callable |
否 | 上传进度回调函数。 |
traffic_limit |
int |
否 | 单链接限速值,单位为 bit/s。 |
完成分块上传
1bos_client.complete_multipart_upload(bucket_name, object_key, upload_id, part_list)
其中,part_list类型是 list,里面每个元素是个 dict ,每个dict包含两个关键字,一个是 partNumber,一个是 eTag。这里支持用户提供各种类型的校验字段( content_crc32、 content_crc32c、 content_crc64ecma)。
示例如下:
1[
2 {
3 'partNumber': 1,
4 'eTag': 'f1c9645dbc14efddc7d8a322685f26eb'
5 },
6 {
7 'partNumber': 2,
8 'eTag': 'f1c9645dbc14efddc7d8a322685f26eb'
9 },
10 {
11 'partNumber': 3,
12 'eTag': '93b885adfe0da089cdf634904fd59f71'
13 }
14]
该方法返回的解析类中可供调用的参数有:
| 参数 | 类型 | 说明 |
|---|---|---|
bucket |
str |
Bucket 名称。 |
key |
str |
Object 名称。 |
e_tag |
str |
完成分块上传后 Object 的 ETag。 |
location |
str |
Object 的 URL。 |
注意: 此对象中包含的 ETag 是上传分块过程中每个 Part 的 ETag ,BOS 收到用户提交的 Part 列表后,会逐一验证每个数据 Part 的有效性。当所有的数据 Part 验证通过后,BOS 将把这些数据 part 组合成一个完整的 Object。
取消分块上传事件
用户可以使用abort_multipart_upload方法取消分块上传:
1bos_client.abort_multipart_upload(bucket_name, object_key, upload_id = upload_id)
获取未完成的分块上传事件
用户可以使用如下两种方法获取Bucket中未完成的分块上传事件:
方法一:
1response = bos_client.list_multipart_uploads(bucket_name)
2for item in response.uploads:
3 print(item.upload_id)
list_multipart_uploads 每次 BOS 最多返回 1000 个 Multipart Upload,BOS 支持 prefix 和 delimiter 过滤。
list_multipart_uploads 方法可供调用的参数还有:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
delimiter |
str |
否 | 分隔符,主要用于实现 list 文件夹的逻辑。 |
key_marker |
str |
否 | Object 按照字典序排序后,本次从 key_marker 后面的一条开始返回。 |
max_uploads |
int |
否 | 本次请求返回 Multipart Uploads 的最大数目,默认 1000,最大 1000。 |
prefix |
str |
否 | Key 前缀,限定返回的 Object Key 必须以此为前缀。 |
list_multipart_uploads 方法返回的解析类中可供调用的参数有:
| 参数 | 类型 | 说明 |
|---|---|---|
bucket |
str |
Bucket 名称。 |
key_marker |
str |
开始上传的分块 Object 名称。 |
next_key_marker |
str |
当指定了 delimiter 且 is_truncated 为 true 时,作为下次查询 Marker 的值。 |
is_truncated |
bool |
指明是否所有查询都返回了;false 表示本次已经返回所有结果,true 表示本次还没有返回所有结果。 |
prefix |
str |
匹配以 prefix 开始到第一次出现 delimiter 字符之间的 Object 作为一组元素返回。 |
common_prefixes |
list |
仅当指定 delimiter 时返回。 |
delimiter |
str |
查询的结束符。 |
max_uploads |
int |
请求返回的最大数目。 |
uploads |
list |
全部未完成的分块上传事件容器。 |
uploads[].owner.id |
str |
Bucket Owner 的用户 ID。 |
uploads[].owner.display_name |
str |
Bucket Owner 的名称。 |
uploads[].key |
str |
分块所属 Object 名称。 |
uploads[].upload_id |
str |
分块上传 ID。 |
uploads[].initiated |
str |
分块上传开始时间。 |
list_all_multipart_uploads 方法返回uploads的生成器(Generator),并且不受单次最大返回 1000 个结果的限制,会返回所有的结果。
方法二:
1uploads = bos_client.list_all_multipart_uploads(bucket_name)
2for item in uploads:
3 print(item.upload_id)
获取所有已上传的块信息
用户可以使用如下两种方法获取某个上传事件中所有已上传的块:
方法一:
1response = bos_client.list_parts(bucket_name, object_key, upload_id)
2for item in response.parts:
3 print(item.part_number)
注意:
- BOS按照PartNumber升序排序。
- 由于网络传输可能出错,所以不推荐用ListParts出来的结果生成最后CompleteMultipartUpload的Part列表。
list_parts 方法可供调用的参数还有:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
max_parts |
int |
否 | BOS 一次最多返回的 Part 数目,默认 1000,最大 1000。 |
part_number_marker |
int |
否 | 按照 partNumber 排序,本次请求的起始 Part 从此 partNumber 的下一个开始返回。 |
list_parts 方法返回的解析类中可供调用的参数有:
| 参数 | 类型 | 说明 |
|---|---|---|
bucket |
str |
Bucket 名称。 |
key |
str |
Object 名称。 |
initiated |
str |
本次分块上传开始时间。 |
max_parts |
int |
请求返回的最大数目。 |
is_truncated |
bool |
指明是否所有查询都返回了;false 表示本次已经返回所有结果,true 表示本次还没有返回所有结果。 |
storage_class |
str |
Object 的存储类型,目前分为标准类型 STANDARD、低频类型 STANDARD_IA、冷存储类型 COLD 和归档类型 ARCHIVE。 |
part_number_marker |
int |
分块开始标记位。 |
parts |
list |
分块列表。 |
parts[].part_number |
int |
分块编号。 |
parts[].last_modified |
str |
此分块最后一次被修改的时间。 |
parts[].e_tag |
str |
每个上传分块的 ETag。 |
parts[].size |
int |
分块内容的大小,单位为字节。 |
upload_id |
str |
本次分块上传的 ID。 |
owner.id |
str |
Bucket Owner 的用户 ID。 |
owner.display_name |
str |
Bucket Owner 的名称。 |
next_part_number_marker |
int |
本次请求返回的最后一条记录的 partNumber,可以作为下一次请求的 part_number_marker。 |
方法二:
1parts = bos_client.list_all_parts(bucket_name, object_key, upload_id = upload_id)
2for item in parts:
3 print(item.part_number)
list_all_parts 方法返回parts的生成器(Generator),并且不受单次最大返回1000个结果的限制,会返回所有的结果。
获取分块上传的Object的存储类型
1response = bos_client.list_parts(
2 bucket_name=bucket_name,
3 key=object_key,
4 upload_id=upload_id
5)
6
7print(response.storage_class)
封装分块上传
在 Python SDK 中,BOS 为用户提供了 put_super_object_from_file() 接口,它对分块上传涉及到的 initiate_multipart_upload、 upload_part_from_file、 complete_multipart_upload 三个方法进行封装,用户只需调用该接口即可完成分块上传。若用户不提供任何校验字段,sdk 将计算 crc32。
1import multiprocessing
2
3file_name = "/path/to/file.zip"
4
5result = bos_client.put_super_object_from_file(
6 bucket_name,
7 object_key,
8 file_name,
9 chunk_size=5,
10 thread_num=multiprocessing.cpu_count()
11)
12
13if result:
14 print("Upload success!")
方法可供调用的参数还有:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
chunk_size |
int |
否 | 分块大小,单位为 MB。默认为 5 MB。 |
thread_num |
int |
否 | 分块上传中线程池中线程的数量,默认等于 CPU 的核数。 |
uploadTaskHandle |
UploadTaskHandle |
否 | 上传任务句柄,可用于取消封装分块上传任务。 |
注意:
chunk_size若不设置可以自适应大小,但单个 Object 仍需满足 BOS 上传大小限制。
若一个大文件耗时很长,用户想结束分块上传,可调用 UploadTaskHandle 中的 cancel() 方法,实现取消分块上传操作。示例如下:
1import multiprocessing
2import threading
3import time
4from baidubce.services.bos.bos_client import UploadTaskHandle
5
6file_name = "/path/to/file.zip"
7upload_task_handle = UploadTaskHandle()
8
9upload_thread = threading.Thread(
10 target=bos_client.put_super_object_from_file,
11 args=(bucket_name, object_key, file_name),
12 kwargs={
13 "chunk_size": 5,
14 "thread_num": multiprocessing.cpu_count(),
15 "uploadTaskHandle": upload_task_handle
16 }
17)
18
19upload_thread.start()
20time.sleep(2)
21upload_task_handle.cancel()
22upload_thread.join()
断点续传上传
当用户向 BOS 上传大文件时,如果网络不稳定或者遇到程序崩溃等情况,则整个上传就失败了,失败前已经上传的部分也作废,用户不得不重头再来。这样做不仅浪费资源,在网络不稳定的情况下,往往重试多次还是无法完成上传。
基于上述场景,BOS 提供了断点续传上传的能力:
- 当网络情况一般的情况下,建议使用三步上传方式,将 Object 分为 1 MB 的块,参考 分块上传。
- 当您的网络情况非常差,推荐使用 AppendObject 的方式进行断点续传,每次 append 较小数据 256 KB,参考 追加上传。
提示
- 断点续传是分片上传的封装和加强,是用分片上传实现的。
- 文件较大或网络环境较差时,推荐使用分片上传。
抓取上传
如下代码用于从指定 URL 抓取资源,并将资源存储到指定的 Bucket 中。此操作需要请求者对该 Bucket 有写权限,每次只能抓取一个 Object,且用户可以自定义 Object 的名称,默认同步抓取。详情可参考 FetchObject 接口。
1from baidubce.services.bos.bos_client import FETCH_MODE_ASYNC
2from baidubce.services.bos import storage_class
3
4fetch_url = "https://example.com/file.txt"
5
6# 默认同步抓取。
7bos_client.fetch_object(
8 bucket_name,
9 object_key,
10 fetch_url
11)
12
13# 异步抓取。
14response = bos_client.fetch_object(
15 bucket_name,
16 object_key,
17 fetch_url,
18 fetch_mode=FETCH_MODE_ASYNC,
19 storage_class=storage_class.COLD
20)
21
22print("jobId:{}, return code:{}, return message:{}".format(
23 response.job_id,
24 response.code,
25 response.message
26))
fetch_object 关键参数说明如下:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
bucket_name |
str |
是 | 目标 Bucket 名称。 |
object_key |
str |
是 | 抓取后保存到 BOS 的 Object 名称。 |
fetch_url |
str |
是 | 待抓取资源的 URL。 |
fetch_mode |
str |
否 | 抓取模式,默认同步抓取;设置为 FETCH_MODE_ASYNC 时为异步抓取。 |
storage_class |
str |
否 | 抓取后 Object 的存储类型。 |
获取上传进度
Python SDK 支持在上传过程中实时提供上传进度信息。目前支持简单上传,追加上传,分块上传。需要在对应接口上增加 progress_callback 参数,并提供进度条回调函数,也可调用工具类中的默认进度条回调函数。
回调函数示例如下:
1import sys
2
3def percentage(consumed_bytes, total_bytes):
4 """进度条回调函数,计算当前完成的百分比。
5
6 :param consumed_bytes: 已经上传或下载的数据量。
7 :param total_bytes: 总数据量。
8 """
9 if total_bytes:
10 rate = int(100 * (float(consumed_bytes) / float(total_bytes)))
11 print("\r{0}% ".format(rate), end="")
12 sys.stdout.flush()
13
14# progress_callback 为可选参数,用于实现进度条功能。
15with open(file_name, "rb") as data_stream:
16 bos_client.put_object(
17 bucket_name,
18 object_key,
19 data_stream,
20 content_length,
21 content_md5=content_md5,
22 progress_callback=percentage
23 )
推荐 使用工具类中的默认进度条回调函数(utils.default_progress_callback),目前支持百分比和进度条展示,示例如下:
1from baidubce import utils
2
3# progress_callback 为可选参数,用于实现进度条功能。
4with open(file_name, "rb") as data_stream:
5 bos_client.put_object(
6 bucket_name,
7 object_key,
8 data_stream,
9 content_length,
10 content_md5=content_md5,
11 progress_callback=utils.default_progress_callback
12 )
- put_object 示例代码
1from baidubce import utils
2
3# 以数据流形式上传 Object。
4with open(file_name, "rb") as data_stream:
5 bos_client.put_object(
6 bucket_name,
7 object_key,
8 data_stream,
9 content_length,
10 content_md5=content_md5,
11 progress_callback=utils.default_progress_callback # progress_callback为可选参数,用于实现进度条功能.
12 )
13
14# 从字符串中上传 Object。
15bos_client.put_object_from_string(
16 bucket_name,
17 object_key,
18 "hello bos",
19 progress_callback=utils.default_progress_callback
20)
21
22# 从文件中上传 Object。
23bos_client.put_object_from_file(
24 bucket_name,
25 object_key,
26 file_name,
27 progress_callback=utils.default_progress_callback
28)
- append_object 示例代码
1from io import BytesIO
2from baidubce import utils
3
4append_data = b"append content"
5
6# 上传 Appendable Object。
7response = bos_client.append_object(
8 bucket_name=bucket_name,
9 key=object_key,
10 data=BytesIO(append_data),
11 content_length=len(append_data),
12 progress_callback=utils.default_progress_callback # progress_callback为可选参数,用于实现进度条功能.
13)
14
15# 从字符串上传 Appendable Object。
16result = bos_client.append_object_from_string(
17 bucket_name=bucket_name,
18 key=object_key,
19 data="append content",
20 progress_callback=utils.default_progress_callback
21)
- upload_part_from_file 示例代码
1from baidubce import utils
2
3# progress_callback 为可选参数,用于实现进度条功能。
4bos_client.upload_part_from_file(
5 bucket_name,
6 object_key,
7 upload_id,
8 part_number,
9 part_size,
10 file_name,
11 offset,
12 progress_callback=utils.default_progress_callback
13)
支持单链接限速
对象存储 BOS 对单 Bucket 的公网带宽阈值为 10 Gbit/s,内网带宽阈值为 50 Gbit/s,当用户的上传或下载占用带宽达到带宽限制阈值时,会返回 RequestRateLimitExceeded 的错误码。为保证用户能够正常使用服务,BOS 支持在进行上传、下载等行为时进行流量控制,保证大流量服务占用带宽不会对其他应用服务造成影响。
上传类请求接口示例
限速值的取值范围为 819200~838860800,单位为 bit/s,即 100 KB/s~100 MB/s。限速值取值必须为数字,BOS 将按照指定的限速值对此次请求进行限速,当限速值不在此范围或不合法时将返回 400 错误码。
1import os
2
3traffic_limit_speed = 819200 * 5
4
5# 上传文件为 Object。
6bos_client.put_object_from_file(
7 bucket_name,
8 object_key,
9 file_name,
10 traffic_limit=traffic_limit_speed
11)
12
13# 分块上传操作示例。
14upload_id = bos_client.initiate_multipart_upload(
15 bucket_name,
16 object_key
17).upload_id
18
19left_size = os.path.getsize(file_name)
20offset = 0
21part_number = 1
22part_list = []
23
24while left_size > 0:
25 part_size = 5 * 1024 * 1024
26 if left_size < part_size:
27 part_size = left_size
28
29 response = bos_client.upload_part_from_file(
30 bucket_name,
31 object_key,
32 upload_id,
33 part_number,
34 part_size,
35 file_name,
36 offset,
37 traffic_limit=traffic_limit_speed
38 )
39
40 left_size -= part_size
41 offset += part_size
42 part_list.append({
43 "partNumber": part_number,
44 "eTag": response.metadata.etag
45 })
46 part_number += 1
47
48# 复制 Object。
49bos_client.copy_object(
50 source_bucket_name,
51 source_key,
52 target_bucket_name,
53 target_key,
54 traffic_limit=traffic_limit_speed
55)
56
57# 追加 Object。append_object 需要提供 data 和 content_length。
58with open(file_name, "rb") as file_stream:
59 bos_client.append_object(
60 bucket_name,
61 object_key,
62 file_stream,
63 os.path.getsize(file_name),
64 traffic_limit=traffic_limit_speed
65 )
66
67# 分片复制。
68bos_client.upload_part_copy(
69 source_bucket_name,
70 source_key,
71 target_bucket_name,
72 target_key,
73 upload_id,
74 part_number,
75 part_size,
76 offset,
77 traffic_limit=traffic_limit_speed
78)
traffic_limit 参数说明如下:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
traffic_limit |
int |
否 | 单链接限速值,单位为 bit/s,取值范围为 819200~838860800。 |
支持设置过期时间
⽀持设置/获取对象过期时间的API包括:
- PutObject
- CopyObject
- MultipartUpload
- MultipartCopy
- GetObject
- GetObjectMeta
对象过期时间通过 x-bce-object-expires Header 设置。使用该能力前,请确认账号已开通对象过期时间能力;未开通时,服务端可能返回 NotImplemented。
上传类请求接口示例
1import os
2
3user_headers = {
4 "x-bce-object-expires": 3
5}
6
7# PutObject 设置对象过期时间。
8put_response = bos_client.put_object_from_file(
9 bucket_name,
10 object_key,
11 file_name,
12 user_headers=user_headers
13)
14
15# GetObjectMeta 获取对象元信息。
16meta_response = bos_client.get_object_meta_data(
17 bucket_name,
18 object_key
19)
20
21# CopyObject 设置对象过期时间。
22copy_response = bos_client.copy_object(
23 bucket_name,
24 object_key,
25 bucket_name,
26 object_key + ".copy",
27 user_headers=user_headers
28)
29
30# GetObjectMeta 获取复制后对象的元信息。
31copy_meta_response = bos_client.get_object_meta_data(
32 bucket_name,
33 object_key + ".copy"
34)
35
36# CompleteMultipartUpload 设置对象过期时间。
37bos_client.complete_multipart_upload(
38 bucket_name,
39 object_key,
40 upload_id,
41 part_list,
42 user_headers=user_headers
43)
x-bce-object-expires 参数说明如下:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
x-bce-object-expires |
int |
否 | Object 过期时间设置值。设置后,可通过 GetObject 或 GetObjectMeta 获取对象过期时间相关信息。 |
设置条件读写字段
BOS 提供了条件读写 header,Python SDK 将这些 header 字段封装在了 cond_read_write 结构体中,这是一个非必要的字段,具体的字段参数信息可参考putObject请求参数。支持条件读写的 API 包括:
- PutObject
- CompleteMultipartUpload
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
If-Match |
str |
否 | 只有 BOS 侧的 Object 的 ETag 与 If-Match 提供的值一致时,本次请求才会成功,否则返回 412 Precondition Failed 错误。 |
If-None-Match |
str |
否 | 只有 BOS 侧的 Object 的 ETag 与 If-None-Match 提供的值不一致时,本次请求才会成功,否则返回 412 Precondition Failed 错误。If-None-Match 支持值为 *,此时仅当 BOS 不存在该对象名的 Object 时,本次请求才会成功。 |
If-Unmodified-Since |
str |
否 | 只有 BOS 侧的 Object 于 If-Unmodified-Since 提供的时间之后未被修改过,本次请求才会成功,否则返回 412 Precondition Failed 错误。当 If-Match 和 If-Unmodified-Since 同时存在时,忽略 If-Unmodified-Since。 |
上传类请求接口示例
1# 示例:使用已有 Object 的 ETag 作为 If-Match 条件。
2cond_read_write = {
3 "If-Match": "111",
4 "If-None-Match": "222",
5 "If-Unmodified-Since": "Wed, 21 Jul 2020 07:23:48 GMT"
6}
7
8put_file_response = bos_client.put_object_from_file(
9 bucket_name,
10 object_key,
11 file_name,
12 cond_read_write=cond_read_write
13)
14
15put_string_response = bos_client.put_object_from_string(
16 bucket_name,
17 object_key,
18 "download",
19 cond_read_write=cond_read_write
20)
21
22# CompleteMultipartUpload 设置条件读写字段。
23bos_client.complete_multipart_upload(
24 bucket_name,
25 object_key,
26 upload_id,
27 part_list,
28 cond_read_write=cond_read_write
29)
使用条件读写字段时,请根据业务场景选择条件。若条件不满足,BOS 会返回 412 Precondition Failed 错误。
评价此篇文章
