Upload objects (Python SDK V2)

更新时间:
复制 MD 格式

Upload objects to a versioning-enabled or versioning-suspended bucket using the OSS SDK for Python V2. The upload method you choose determines how OSS assigns version IDs and how previous versions are handled.

How versioning affects uploads

Upload typeVersioning-enabledVersioning-suspended
Simple upload (PutObject)OSS generates a unique version ID, returned in the x-oss-version-id response headerVersion ID is null; uploading an object with the same name overwrites the existing object
Append upload (AppendObject)Operates only on the current version; OSS does not create a previous version
Multipart upload (CompleteMultipartUpload)OSS generates a unique version ID upon completion, returned in the x-oss-version-id response header

Prerequisites

Before you begin, make sure you have:

By default, Alibaba Cloud accounts have full permissions. RAM users and RAM roles have no permissions by default and must be granted access explicitly.

Permissions

APIActionWhen required
PutObjectoss:PutObjectAlways
PutObjectoss:PutObjectTaggingWhen setting object tags via the x-oss-tagging header
PutObjectkms:GenerateDataKey, kms:DecryptWhen object metadata includes X-Oss-Server-Side-Encryption: KMS

Simple upload

PutObject uploads an object in a single request. For versioning-enabled buckets, the version ID of the uploaded object is returned as result.version_id, which corresponds to the x-oss-version-id response header.

The sample code uses the cn-hangzhou region and its public endpoint. To access OSS from other Alibaba Cloud services in the same region, use the internal endpoint instead.
import argparse
import requests
import alibabacloud_oss_v2 as oss

parser = argparse.ArgumentParser(description="put object sample")
parser.add_argument('--region', help='The region in which the bucket is located.', required=True)
parser.add_argument('--bucket', help='The name of the bucket.', required=True)
parser.add_argument('--endpoint', help='The domain names that other services can use to access OSS')
parser.add_argument('--key', help='The name of the object.', required=True)

def main():
    args = parser.parse_args()

    # Load credentials from environment variables for identity verification.
    credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()

    cfg = oss.config.load_default()
    cfg.credentials_provider = credentials_provider
    cfg.region = args.region
    if args.endpoint is not None:
        cfg.endpoint = args.endpoint

    client = oss.Client(cfg)

    # Read the local file to upload.
    local_file_path = '/yourLocalFilePath/yourFileName'
    with open(local_file_path, 'rb') as file:
        data = file.read()

    result = client.put_object(oss.PutObjectRequest(
        bucket=args.bucket,
        key=args.key,
        body=data,
    ))

    # result.version_id is the value of the x-oss-version-id response header.
    print(f'status code: {result.status_code},'
          f' request id: {result.request_id},'
          f' content md5: {result.content_md5},'
          f' etag: {result.etag},'
          f' hash crc64: {result.hash_crc64},'
          f' version id: {result.version_id},'
    )

if __name__ == "__main__":
    main()

Append upload

AppendObject appends data to an existing appendable object. In versioning-enabled buckets, AppendObject operates only on the current version of an appendable object.

Keep the following versioning behaviors in mind when using append upload:
AppendObject on the current version does not create a previous version.
PutObject or DeleteObject on the current version of an appendable object converts it to a previous version. Data can no longer be appended to that version.
AppendObject cannot be performed on non-appendable objects (normal objects or delete markers).

Each append call requires the position parameter, which specifies where to start writing. Set position=0 for the first append, then use result.next_position for each subsequent append.

import argparse
import alibabacloud_oss_v2 as oss

parser = argparse.ArgumentParser(description="append object sample")
parser.add_argument('--region', help='The region in which the bucket is located.', required=True)
parser.add_argument('--bucket', help='The name of the bucket.', required=True)
parser.add_argument('--endpoint', help='The domain names that other services can use to access OSS')
parser.add_argument('--key', help='The name of the object.', required=True)

def main():
    args = parser.parse_args()

    credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
    cfg = oss.config.load_default()
    cfg.credentials_provider = credentials_provider
    cfg.region = args.region
    if args.endpoint is not None:
        cfg.endpoint = args.endpoint

    client = oss.Client(cfg)

    data1 = b'hello'
    data2 = b' world'

    # First append: position must be 0.
    result = client.append_object(oss.AppendObjectRequest(
        bucket=args.bucket,
        key=args.key,
        position=0,
        body=data1,
    ))

    print(f'status code: {result.status_code},'
          f' request id: {result.request_id},'
          f' version id: {result.version_id},'
          f' hash crc64: {result.hash_crc64},'
          f' next position: {result.next_position},'
          f' server side encryption: {result.server_side_encryption},'
          f' server side data encryption: {result.server_side_data_encryption},'
    )

    # Second append: use next_position from the previous result.
    result = client.append_object(oss.AppendObjectRequest(
        bucket=args.bucket,
        key=args.key,
        position=result.next_position,
        body=data2,
    ))

    print(f'status code: {result.status_code},'
          f' request id: {result.request_id},'
          f' version id: {result.version_id},'
          f' hash crc64: {result.hash_crc64},'
          f' next position: {result.next_position},'
          f' server side encryption: {result.server_side_encryption},'
          f' server side data encryption: {result.server_side_data_encryption},'
    )

if __name__ == "__main__":
    main()

Multipart upload

Multipart upload splits a large file into parts and uploads them independently, then assembles them into a single object. OSS assigns a unique version ID when CompleteMultipartUpload completes, returned in the x-oss-version-id response header.

The process has three stages:

  1. Initiate — call initiate_multipart_upload to get an upload ID.

  2. Upload parts — call upload_part for each chunk, collecting the part number and ETag from each response.

  3. Complete — call complete_multipart_upload with the sorted part list to assemble the object.

import os
import argparse
import alibabacloud_oss_v2 as oss

parser = argparse.ArgumentParser(description="multipart upload sample")
parser.add_argument('--region', help='The region in which the bucket is located.', required=True)
parser.add_argument('--bucket', help='The name of the bucket.', required=True)
parser.add_argument('--endpoint', help='The domain names that other services can use to access OSS')
parser.add_argument('--key', help='The name of the object.', required=True)
parser.add_argument('--file_path', help='The path of Upload file.', required=True)

def main():
    args = parser.parse_args()

    credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
    cfg = oss.config.load_default()
    cfg.credentials_provider = credentials_provider
    cfg.region = args.region
    if args.endpoint is not None:
        cfg.endpoint = args.endpoint

    client = oss.Client(cfg)

    # Stage 1: Initiate the multipart upload to obtain an upload ID.
    result = client.initiate_multipart_upload(oss.InitiateMultipartUploadRequest(
        bucket=args.bucket,
        key=args.key,
    ))

    # Part size: 5 MB per part. The last part can be smaller.
    part_size = 5 * 1024 * 1024
    data_size = os.path.getsize(args.file_path)
    part_number = 1
    upload_parts = []

    # Stage 2: Upload parts sequentially.
    with open(args.file_path, 'rb') as f:
        for start in range(0, data_size, part_size):
            n = part_size
            if start + n > data_size:
                n = data_size - start

            reader = oss.io_utils.SectionReader(oss.io_utils.ReadAtReader(f), start, n)

            up_result = client.upload_part(oss.UploadPartRequest(
                bucket=args.bucket,
                key=args.key,
                upload_id=result.upload_id,
                part_number=part_number,
                body=reader
            ))

            print(f'status code: {up_result.status_code},'
                  f' request id: {up_result.request_id},'
                  f' part number: {part_number},'
                  f' content md5: {up_result.content_md5},'
                  f' etag: {up_result.etag},'
                  f' hash crc64: {up_result.hash_crc64},'
                  )

            upload_parts.append(oss.UploadPart(part_number=part_number, etag=up_result.etag))
            part_number += 1

    # Stage 3: Complete the upload. Parts must be sorted by part number.
    parts = sorted(upload_parts, key=lambda p: p.part_number)

    result = client.complete_multipart_upload(oss.CompleteMultipartUploadRequest(
        bucket=args.bucket,
        key=args.key,
        upload_id=result.upload_id,
        complete_multipart_upload=oss.CompleteMultipartUpload(
            parts=parts
        )
    ))

    # result.version_id is the value of the x-oss-version-id response header.
    print(f'status code: {result.status_code},'
          f' request id: {result.request_id},'
          f' bucket: {result.bucket},'
          f' key: {result.key},'
          f' location: {result.location},'
          f' etag: {result.etag},'
          f' encoding type: {result.encoding_type},'
          f' hash crc64: {result.hash_crc64},'
          f' version id: {result.version_id},'
    )

if __name__ == "__main__":
    main()