Append upload

Updated at:

Append upload lets you append content directly to the end of an existing appendable object.

Prerequisites

A bucket is created. For more information, see Create buckets.

Background information

Objects created using simple upload are Normal objects, and objects created using multipart upload are Multipart objects. After an upload is complete, the content of these two object types is fixed. You can only read them. You cannot modify them. If the object content changes, you must upload an object with the same name again to overwrite the existing content.

Because of this limitation, if you use these methods to upload real-time video streams from sources such as video surveillance systems or ApsaraVideo Live, you can only chunk the video stream into smaller pieces and continuously upload them as new objects. This approach has the following disadvantages:

  • The software architecture is complex. You must manage details such as file chunking.

  • You need a location to store metadata, such as a list of generated objects. Then, each request must repeatedly read the metadata to check whether new objects are generated. This places a heavy load on the server. The client also needs to send two network requests each time, which can increase latency.

  • If you chunk objects into smaller pieces, you can reduce data latency. However, many small objects makes management complex. If you chunk objects into larger pieces, data latency increases significantly.

To update the content of an uploaded video stream in real-time, you can first splice the video locally. Then, you can upload the video using the append upload (AppendObject) feature provided by Object Storage Service (OSS). This creates an appendable object. You can directly append content to an appendable object. The appended data is readable immediately after each append operation.

Benefits

With append upload, you can upload video data to the same object as soon as the data is generated. The client only needs to periodically retrieve the object's length and compare it with the previously read length. If new readable data is found, the client triggers a read operation to retrieve the newly uploaded data. This method simplifies the architecture and improves extensibility.

Limits

  • Size limit

    The object size cannot exceed 5 GB.

  • Operation limits

    • You cannot use append upload to upload Cold Archive or Deep Cold Archive objects.

    • Append upload does not support upload callbacks.

Notes

  • If the object does not exist, calling the AppendObject API operation creates an appendable object.

  • If the object already exists:

    • If the object is an appendable object and the specified append position equals the current object length, the content is appended to the end of the object.

    • If the object is an appendable object but the specified append position does not equal the current object length, a PositionNotEqualToLength exception is thrown.

    • If the object is a non-appendable object, such as a Normal object uploaded using simple upload, an ObjectNotAppendable exception is thrown.

Methods

Use an Alibaba Cloud SDK

The following sections provide code examples for append uploads using common software development kits (SDKs). For code examples that use other SDKs, see SDK overview.

import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.AppendObjectRequest;
import com.aliyun.oss.model.AppendObjectResult;
import com.aliyun.oss.model.ObjectMetadata;
import java.io.ByteArrayInputStream;

public class Demo {

    public static void main(String[] args) throws Exception {
        // The endpoint of the China (Hangzhou) region is used as an example. Specify the actual endpoint.
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        // Obtain access credentials from environment variables. Before running the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are set.
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // Specify the bucket name, for example, examplebucket.
        String bucketName = "examplebucket";
        // Specify the full path of the object. The full path cannot contain the bucket name. Example: exampledir/exampleobject.txt.
        String objectName = "exampledir/exampleobject.txt";
        String content1 = "Hello OSS A \n";
        String content2 = "Hello OSS B \n";
        String content3 = "Hello OSS C \n";
        // Specify the region where the bucket is located. For example, if the bucket is in the China (Hangzhou) region, set Region to cn-hangzhou.
        String region = "cn-hangzhou";

        // Create an OSSClient instance.
        // When the OSSClient instance is no longer in use, call the shutdown method to release resources.
        ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
        clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);        
        OSS ossClient = OSSClientBuilder.create()
        .endpoint(endpoint)
        .credentialsProvider(credentialsProvider)
        .clientConfiguration(clientBuilderConfiguration)
        .region(region)               
        .build();

        try {
            ObjectMetadata meta = new ObjectMetadata();
            // Specify the content type of the upload.
            meta.setContentType("text/plain");
            // Specify the web page caching behavior for the object.
            //meta.setCacheControl("no-cache");
            // Specify the name of the object when it is downloaded.
            //meta.setContentDisposition("attachment;filename=oss_download.txt");
            // Specify the content encoding format of the object.
            //meta.setContentEncoding(OSSConstants.DEFAULT_CHARSET_NAME);
            // This request header is used to check whether the message content is consistent with the content sent.
            //meta.setContentMD5("ohhnqLBJFiKkPSBO1eNaUA==");
            // Specify the expiration time.
            //try {
            //    meta.setExpirationTime(DateUtil.parseRfc822Date("Wed, 08 Jul 2022 16:57:01 GMT"));
            //} catch (ParseException e) {
            //    e.printStackTrace();
            //}
            // Specify the server-side encryption method. In this example, server-side encryption with OSS-managed keys (SSE-OSS) is used.
            //meta.setServerSideEncryption(ObjectMetadata.AES_256_SERVER_SIDE_ENCRYPTION);
            // Specify the access permissions of the object. In this example, the private access permission is specified.
            //meta.setObjectAcl(CannedAccessControlList.Private);
            // Specify the storage class of the object.
            //meta.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard);
            // You can add x-oss-meta-* when you create an AppendObject. You cannot carry this parameter for subsequent appends. If you configure a parameter prefixed with x-oss-meta-*, the parameter is considered metadata.
            //meta.setHeader("x-oss-meta-author", "Alice");

            // Set multiple parameters through AppendObjectRequest.
            AppendObjectRequest appendObjectRequest = new AppendObjectRequest(bucketName, objectName, new ByteArrayInputStream(content1.getBytes()),meta);

            // Set a single parameter through AppendObjectRequest.
            // Set the bucket name.
            //appendObjectRequest.setBucketName(bucketName);
            // Set the object name.
            //appendObjectRequest.setKey(objectName);
            // Set the content to be appended. The type can be InputStream or File. In this example, the type is InputStream.
            //appendObjectRequest.setInputStream(new ByteArrayInputStream(content1.getBytes()));
            // Set the content to be appended. The type can be InputStream or File. In this example, the type is File.
            //appendObjectRequest.setFile(new File("D:\\localpath\\examplefile.txt"));
            // Specify the metadata of the file. This is valid only for the first append.
            //appendObjectRequest.setMetadata(meta);

            // First append.
            // Set the append position of the file.
            appendObjectRequest.setPosition(0L);
            AppendObjectResult appendObjectResult = ossClient.appendObject(appendObjectRequest);
            // The 64-bit CRC value of the file.
            System.out.println(appendObjectResult.getObjectCRC());

            // Second append.
            // nextPosition indicates the position that should be provided in the next request, which is the current length of the file.
            appendObjectRequest.setPosition(appendObjectResult.getNextPosition());
            appendObjectRequest.setInputStream(new ByteArrayInputStream(content2.getBytes()));
            appendObjectResult = ossClient.appendObject(appendObjectRequest);

            // Third append.
            appendObjectRequest.setPosition(appendObjectResult.getNextPosition());
            appendObjectRequest.setInputStream(new ByteArrayInputStream(content3.getBytes()));
            appendObjectResult = ossClient.appendObject(appendObjectRequest);
        } 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();
            }
        }
    }
}
const OSS = require('ali-oss')

const client = new OSS({
  // Set region to the region where the bucket is located. For example, if the bucket is in the China (Hangzhou) region, set region to oss-cn-hangzhou.
  region: 'yourRegion',
  // Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured.
  accessKeyId: process.env.OSS_ACCESS_KEY_ID,
  accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET,
  authorizationV4: true,
  // Specify the bucket name. Example: examplebucket.
  bucket: 'examplebucket',
});

const headers = {    
  // Specify the access permissions of the object.
  'x-oss-object-acl': 'private',
  // Specify the storage class of the object.
  'x-oss-storage-class': 'Standard',  
  // Specify the server-side encryption method. In this example, server-side encryption with OSS-managed keys (SSE-OSS) is used.
  'x-oss-server-side-encryption': 'AES256',  
};

async function append () {
  // Perform the first append upload. The return value indicates the position for the next append operation.
  // objectName specifies the full path of the object without the bucket name. Example: destfolder/examplefile.txt.
  // localFile specifies the full path of the local file, including the file extension. Example: /users/local/examplefile.txt.
  let result = await client.append('objectName', 'localFile'
  // Custom headers and metadata.
  //,{headers} 
  )

  // Perform the second append upload. The position for the next append operation is the length of the object before this append operation (Content-Length).
  result = await client.append('objectName', 'localFile', {
    position: result.nextAppendPosition
  })
}

append();
using Aliyun.OSS;
using Aliyun.OSS.Common;

// Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. 
var endpoint = "yourEndpoint";
// Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. 
var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID");
var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET");
// Specify the name of the bucket. Example: examplebucket. 
var bucketName = "examplebucket";
// Specify the full path of the object. Do not include the bucket name in the full path. Example: exampledir/exampleobject.txt. 
var objectName = "exampledir/exampleobject.txt";
// Specify the full path of the local file. Example: D:\\localpath\\examplefile.txt. By default, if you do not specify the path of the local file, the file is uploaded from the path of the project to which the sample program belongs. 
var localFilename = "D:\\localpath\\examplefile.txt";
// Specify the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the region to cn-hangzhou.
const string region = "cn-hangzhou";

// Create a ClientConfiguration instance and modify the default parameters based on your requirements.
var conf = new ClientConfiguration();

// Use the signature algorithm V4.
conf.SignatureVersion = SignatureVersion.V4;

// Create an OSSClient instance.
var client = new OssClient(endpoint, accessKeyId, accessKeySecret, conf);
c.SetRegion(region);
// The position for the first append upload is 0, and the position for the next append upload is included in the response. The position from which the next append operation starts is the current length of the object. 
long position = 0;
try
{
    var metadata = client.GetObjectMetadata(bucketName, objectName);
    position = metadata.ContentLength;
}
catch (Exception) { }
try
{
    using (var fs = File.Open(localFilename, FileMode.Open))
    {
        var request = new AppendObjectRequest(bucketName, objectName)
        {
            ObjectMetadata = new ObjectMetadata(),
            Content = fs,
            Position = position
        };
        // Perform the append operation. 
        var result = client.AppendObject(request);
        // Specify the position from which the append operation starts. 
        position = result.NextAppendPosition;
        Console.WriteLine("Append object succeeded, next append position:{0}", position);
    }
    // Query the position from which the next append operation starts and perform the second append operation. 
    using (var fs = File.Open(localFilename, FileMode.Open))
    {
        var request = new AppendObjectRequest(bucketName, objectName)
        {
            ObjectMetadata = new ObjectMetadata(),
            Content = fs,
            Position = position
        };
        var result = client.AppendObject(request);
        position = result.NextAppendPosition;
        Console.WriteLine("Append object succeeded, next append position:{0}", position);
    }
}
catch (Exception ex)
{
    Console.WriteLine("Append object failed, {0}", ex.Message);
}
// Specify the bucket name, the full path of the object, and the full path of the local file. Example: examplebucket, exampledir/exampleobject.txt, and /storage/emulated/0/oss/examplefile.txt.
// The full path of the object cannot contain the bucket name.
AppendObjectRequest append = new AppendObjectRequest("examplebucket", "exampledir/exampleobject.txt", "/storage/emulated/0/oss/examplefile.txt");

ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType("text/plain");
append.setMetadata(metadata);

// Set the append position.
append.setPosition(0);

// Set the callback.
append.setProgressCallback(new OSSProgressCallback<AppendObjectRequest>() {
    @Override
    public void onProgress(AppendObjectRequest request, long currentSize, long totalSize) {
        Log.d("AppendObject", "currentSize: " + currentSize + " totalSize: " + totalSize);
    }
});
// Asynchronously append data.
OSSAsyncTask task = oss.asyncAppendObject(append, new OSSCompletedCallback<AppendObjectRequest, AppendObjectResult>() {
    @Override
    public void onSuccess(AppendObjectRequest request, AppendObjectResult result) {
        Log.d("AppendObject", "AppendSuccess");
        Log.d("NextPosition", "" + result.getNextPosition());
    }

    @Override
    public void onFailure(AppendObjectRequest request, ClientException clientExcepion, ServiceException serviceException) {
        // Handle exceptions.
    }
});
OSSAppendObjectRequest * append = [OSSAppendObjectRequest new];
// Configure the required fields. `bucketName` specifies the name of the bucket. `objectKey`, which is equivalent to `objectName`, specifies the full path of the object to which you want to append data. The path must include the file extension, for example, `abc/efg/123.jpg`.
append.bucketName = @"<bucketName>";
append.objectKey = @"<objectKey>";
// Specify the position for the first append upload.
append.appendPosition = 0; 
NSString * docDir = [self getDocumentDirectory];
append.uploadingFileURL = [NSURL fileURLWithPath:@"<yourLocalFilePath>"];
// The following fields are optional.
append.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {
    NSLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);
};
// append.contentType = @"";
// append.contentMd5 = @"";
// append.contentEncoding = @"";
// append.contentDisposition = @"";
OSSTask * appendTask = [client appendObject:append];
[appendTask continueWithBlock:^id(OSSTask *task) {
    NSLog(@"objectKey: %@", append.objectKey);
    if (!task.error) {
        NSLog(@"append object success!");
        OSSAppendObjectResult * result = task.result;
        NSString * etag = result.eTag;
        long nextPosition = result.xOssNextAppendPosition;
    } else {
        NSLog(@"append object failed, error: %@" , task.error);
    }
    return nil;
}];
#include <alibabacloud/oss/OssClient.h>
using namespace AlibabaCloud::OSS;

int main(void)
{
    /* Initialize the OSS account information. */
            
    /* Set yourEndpoint to the Endpoint of the region where the bucket is located. For example, if the bucket is in the China (Hangzhou) region, set the Endpoint to https://oss-cn-hangzhou.aliyuncs.com. */
    std::string Endpoint = "yourEndpoint";
    /* Set yourRegion to the region where the bucket is located. For example, if the bucket is in the China (Hangzhou) region, set the Region to cn-hangzhou. */
    std::string Region = "yourRegion";
    /* Specify the bucket name, for example, examplebucket. */
    std::string BucketName = "examplebucket";
    /* Specify the full path of the object. The full path cannot contain the bucket name. For example, exampledir/exampleobject.txt. */
    std::string ObjectName = "exampledir/exampleobject.txt";

    /* Initialize network resources. */
    InitializeSdk();

    ClientConfiguration conf;
    conf.signatureVersion = SignatureVersionType::V4;
    /* Obtain access credentials from environment variables. Before running this sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are set. */
    auto credentialsProvider = std::make_shared<EnvironmentVariableCredentialsProvider>();
    OssClient client(Endpoint, credentialsProvider, conf);
    client.SetRegion(Region);

    auto meta = ObjectMetaData();
    meta.setContentType("text/plain");

    /* The position for the first append operation is 0. The return value indicates the position for the next append operation. The position for subsequent append operations is the length of the object before the append. */
    std::shared_ptr<std::iostream> content1 = std::make_shared<std::stringstream>();
    *content1 <<"Thank you for using Alibaba Cloud Object Storage Service!";
    AppendObjectRequest request(BucketName, ObjectName, content1, meta);
    request.setPosition(0L);

    /* Append data to the object for the first time. */
    auto result = client.AppendObject(request);

    if (!result.isSuccess()) {
        /* Handle exceptions. */
        std::cout << "AppendObject fail" <<
        ",code:" << result.error().Code() <<
        ",message:" << result.error().Message() <<
        ",requestId:" << result.error().RequestId() << std::endl;
        return -1;
    }

    std::shared_ptr<std::iostream> content2 = std::make_shared<std::stringstream>();
    *content2 <<"Thank you for using Alibaba Cloud Object Storage Service!";
    auto position = result.result().Length();
    AppendObjectRequest appendObjectRequest(BucketName, ObjectName, content2);
    appendObjectRequest.setPosition(position);

    /* Append data to the object for the second time. */
    auto outcome = client.AppendObject(appendObjectRequest);

    if (!outcome.isSuccess()) {
        /* Handle exceptions. */
        std::cout << "AppendObject fail" <<
        ",code:" << outcome.error().Code() <<
        ",message:" << outcome.error().Message() <<
        ",requestId:" << outcome.error().RequestId() << std::endl;
        return -1;
    }

    /* Release network resources. */
    ShutdownSdk();
    return 0;
}
#include "oss_api.h"
#include "aos_http_io.h"
/* Set yourEndpoint to the Endpoint of the region where the bucket is located. For example, for the China (Hangzhou) region, set the Endpoint to https://oss-cn-hangzhou.aliyuncs.com. */
const char *endpoint = "yourEndpoint";

/* Specify the bucket name. For example, examplebucket. */
const char *bucket_name = "examplebucket";
/* Specify the full path of the object. The full path cannot contain the bucket name. For example, exampledir/exampleobject.txt. */
const char *object_name = "exampledir/exampleobject.txt";
const char *object_content = "More than just cloud.";
/* Set yourRegion to the region where the bucket is located. For example, for the China (Hangzhou) region, set the region to cn-hangzhou. */
const char *region = "yourRegion";
void init_options(oss_request_options_t *options)
{
    options->config = oss_config_create(options->pool);
    /* Initialize the aos_string_t type with a char* string. */
    aos_str_set(&options->config->endpoint, endpoint);
    /* Obtain access credentials from environment variables. Before running this sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are set. */    
    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"));
    // Configure the following two parameters.
    aos_str_set(&options->config->region, region);
    options->config->signature_version = 4;
    /* Specifies whether a CNAME is used. 0 indicates that a CNAME is not used. */
    options->config->is_cname = 0;
    /* Set network parameters, such as the timeout period. */
    options->ctl = aos_http_controller_create(options->pool, 0);
}
int main(int argc, char *argv[])
{
    /* Call the aos_http_io_initialize method at the program entry to initialize global resources, such as the network and memory. */
    if (aos_http_io_initialize(NULL, 0) != AOSE_OK) {
        exit(1);
    }
    /* The memory pool for memory management is equivalent to apr_pool_t. The implementation code is in the apr library. */
    aos_pool_t *pool;
    /* Create a new memory pool. The second parameter is NULL, which indicates that the new memory pool does not inherit from another memory pool. */
    aos_pool_create(&pool, NULL);
    /* Create and initialize options. This parameter includes global configuration information such as endpoint, access_key_id, access_key_secret, is_cname, and curl. */
    oss_request_options_t *oss_client_options;
    /* Allocate memory to options in the memory pool. */
    oss_client_options = oss_request_options_create(pool);
    /* Initialize the client options oss_client_options. */
    init_options(oss_client_options);
    /* Initialize parameters. */
    aos_string_t bucket;
    aos_string_t object;
    aos_list_t buffer;
    int64_t position = 0;
    char *next_append_position = NULL;
    aos_buf_t *content = NULL;
    aos_table_t *headers1 = NULL;
    aos_table_t *headers2 = NULL;
    aos_table_t *resp_headers = NULL; 
    aos_status_t *resp_status = NULL; 
    aos_str_set(&bucket, bucket_name);
    aos_str_set(&object, object_name);
    headers1 = aos_table_make(pool, 0);
    /* Get the starting append position. */
    resp_status = oss_head_object(oss_client_options, &bucket, &object, headers1, &resp_headers);
    if (aos_status_is_ok(resp_status)) {
        next_append_position = (char*)(apr_table_get(resp_headers, "x-oss-next-append-position"));
        position = atoi(next_append_position);
    }
    /* Append the object. */
    headers2 = aos_table_make(pool, 0);
    aos_list_init(&buffer);
    content = aos_buf_pack(pool, object_content, strlen(object_content));
    aos_list_add_tail(&content->node, &buffer);
    resp_status = oss_append_object_from_buffer(oss_client_options, &bucket, &object, position, &buffer, headers2, &resp_headers);
    if (aos_status_is_ok(resp_status)) {
        printf("append object from buffer succeeded\n");
    } else {
        printf("append object from buffer failed\n");
    }
    /* Release the memory pool. This releases the memory allocated to resources during the request. */
    aos_pool_destroy(pool);
    /* Release the previously allocated global resources. */
    aos_http_io_deinitialize();
    return 0;
}
require 'aliyun/oss'

client = Aliyun::OSS::Client.new(
  # The China (Hangzhou) region is used as an example. Specify the actual region.
  endpoint: 'https://oss-cn-hangzhou.aliyuncs.com',
  # Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are set.
  access_key_id: ENV['OSS_ACCESS_KEY_ID'],
  access_key_secret: ENV['OSS_ACCESS_KEY_SECRET']
)

# Specify the bucket name, for example, examplebucket.
bucket = client.get_bucket('examplebucket')
# Specify the full path of the object. The full path cannot contain the bucket name.
bucket.append_object('my-object', 0)

# Append content to the end of the file.
next_pos = bucket.append_object('my-object', 0) do |stream|
  100.times { |i| stream << i.to_s }
end
next_pos = bucket.append_object('my-object', next_pos, :file => 'local-file-1')
next_pos = bucket.append_object('my-object', next_pos, :file => 'local-file-2')
package main

import (
	"context"
	"flag"
	"log"
	"strings"

	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
)

// Define global variables.
var (
	region     string
	bucketName string
	objectName string
)

// The init function is used to initialize command-line parameters.
func init() {
	flag.StringVar(&region, "region", "", "The region in which the bucket is located.")
	flag.StringVar(&bucketName, "bucket", "", "The name of the bucket.")
	flag.StringVar(&objectName, "object", "", "The name of the object.")
}

func main() {
	// Parse command-line parameters.
	flag.Parse()

	// Define the initial position for the append upload.
	var (
		position = int64(0)
	)

	// Check whether the bucket name is empty.
	if len(bucketName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, bucket name required")
	}

	// Check whether the region is empty.
	if len(region) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, region required")
	}

	// Check whether the object name is empty.
	if len(objectName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, object name required")
	}

	// Load the default configurations and set the credential provider and region.
	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
		WithRegion(region)

	// Create an OSS client.
	client := oss.NewClient(cfg)

	// Define the content to append.
	content := "hi append object"

	// Create an AppendObject request.
	request := &oss.AppendObjectRequest{
		Bucket:   oss.Ptr(bucketName),
		Key:      oss.Ptr(objectName),
		Position: oss.Ptr(position),
		Body:     strings.NewReader(content),
	}

	// Execute the AppendObject request and process the result.
	// The position for the first append upload is 0. The return value contains the position for the next append upload.
	result, err := client.AppendObject(context.TODO(), request)
	if err != nil {
		log.Fatalf("failed to append object %v", err)
	}

	// Create the second AppendObject request.
	request = &oss.AppendObjectRequest{
		Bucket:   oss.Ptr(bucketName),
		Key:      oss.Ptr(objectName),
		Position: oss.Ptr(result.NextPosition), // Obtain NextPosition from the return value of the first AppendObject request.
		Body:     strings.NewReader("hi append object"),
	}

	// Execute the second AppendObject request and process the result.
	result, err = client.AppendObject(context.TODO(), request)
	if err != nil {
		log.Fatalf("failed to append object %v", err)
	}

	log.Printf("append object result:%#v\n", result)
}
import argparse
import alibabacloud_oss_v2 as oss

# Create a command-line argument parser.
parser = argparse.ArgumentParser(description="append object sample")

# Add command-line arguments.
# --region: Specifies the region where the OSS bucket is located.
parser.add_argument('--region', help='The region in which the bucket is located.', required=True)
# --bucket: Specifies the name of the bucket to operate on.
parser.add_argument('--bucket', help='The name of the bucket.', required=True)
# --endpoint: An optional parameter that specifies the domain name used to access the OSS service.
parser.add_argument('--endpoint', help='The domain names that other services can use to access OSS')
# --key: Specifies the key of the object (file) in OSS.
parser.add_argument('--key', help='The name of the object.', required=True)

def main():
    # Parse the command-line arguments.
    args = parser.parse_args()

    # Load the authentication information required for OSS from environment variables.
    credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()

    # Create a configuration object using the default configurations provided by the SDK.
    cfg = oss.config.load_default()

    # Set the credential provider to the previously created object.
    cfg.credentials_provider = credentials_provider

    # Set the region for the OSS client based on user input.
    cfg.region = args.region

    # If the user provides a custom endpoint, update the configuration.
    if args.endpoint is not None:
        cfg.endpoint = args.endpoint

    # Create an OSS client instance using the preceding configurations.
    client = oss.Client(cfg)

    # Define the data to be appended.
    data1 = b'hello'
    data2 = b' world'

    # Append data for the first time.
    result = client.append_object(oss.AppendObjectRequest(
        bucket=args.bucket,  # Specify the destination bucket.
        key=args.key,  # Specify the key of the object.
        position=0,  # The starting position for appending, which is initially 0.
        body=data1,  # The data to be appended.
    ))

    # Print the result of the first append operation.
    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},' 
    )

    # Append data for the second time.
    result = client.append_object(oss.AppendObjectRequest(
        bucket=args.bucket,  # Specify the destination bucket.
        key=args.key,  # Specify the key of the object.
        position=result.next_position,  # Start from the next position of the previous append operation.
        body=data2,  # The data to be appended.
    ))

    # Print the result of the second append operation.
    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},'
    )

# When this script is run directly, call the main function.
if __name__ == "__main__":
    main()
<?php

// Introduce autoload files to load dependency libraries.
require_once __DIR__ . '/../vendor/autoload.php';

use AlibabaCloud\Oss\V2 as Oss;

// Define and describe command-line parameters.
$optsdesc = [
    "region" => ['help' => 'The region in which the bucket is located.', 'required' => True], // (Required) Specify the region in which the bucket is located.
    "endpoint" => ['help' => 'The domain names that other services can use to access OSS.', 'required' => False], // (Optional) Specify the endpoint for accessing OSS.
    "bucket" => ['help' => 'The name of the bucket', 'required' => True], // (Required) Specify the name of the bucket.
    "key" => ['help' => 'The name of the object', 'required' => True], // (Required) Specify the name of the object.
];

// Convert the descriptions to a list of long options required by getopt.
// Add a colon (:) to the end of each parameter to indicate that a value is required.
$longopts = \array_map(function ($key) {
    return "$key:";
}, array_keys($optsdesc));

// Parse the command-line parameters.
$options = getopt("", $longopts);

// Check whether the required parameters are configured.
foreach ($optsdesc as $key => $value) {
    if ($value['required'] === True && empty($options[$key])) {
        $help = $value['help']; // Obtain help information for the parameters.
        echo "Error: the following arguments are required: --$key, $help" . PHP_EOL;
        exit(1); // Exit the program if a required parameter is missing.
    }
}

// Assign the values parsed from the command-line parameters to the corresponding variables.
$region = $options["region"]; // The region in which the bucket is located.
$bucket = $options["bucket"]; // The name of the bucket.
$key = $options["key"];       // The name of the object.

// Load access credentials from environment variables.
// Use EnvironmentVariableCredentialsProvider to retrieve the AccessKey ID and AccessKey secret from environment variables.
$credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider();

// Use the default configuration of the SDK.
$cfg = Oss\Config::loadDefault();
$cfg->setCredentialsProvider($credentialsProvider); // Specify the credential provider.
$cfg->setRegion($region); // Specify the region in which the bucket is located.
if (isset($options["endpoint"])) {
    $cfg->setEndpoint($options["endpoint"]); // Specify the endpoint if one is provided.
}

// Create an OSSClient instance.
$client = new Oss\Client($cfg);

// Specify the content that you want to append.
$data='Hello Append Object'; // Replace the sample data with your actual content.

// Create an AppendObjectRequest object to append data to a specific object.
$request = new Oss\Models\AppendObjectRequest(bucket: $bucket, key: $key);
$request->body = Oss\Utils::streamFor($data); // Specify that the HTTP request body is a binary stream.
$request->position = 0; // Set the position from which the first append operation starts to 0.

// Perform the append upload operation.
$result = $client->appendObject($request);

// Display the result.
// Display the HTTP status code and the request ID to check whether the request succeeded.
printf(
    'status code:' . $result->statusCode . PHP_EOL . // The HTTP status code. For example, HTTP status code 200 indicates that the request succeeded.
    'request id:' . $result->requestId . PHP_EOL .    // The request ID, which is used to debug or trace a request.
    'next append position:' . $result->nextPosition . PHP_EOL // Specify the position from which the next append operation starts.
);

Use the ossutil command line interface

You can use the ossutil command line interface (CLI) to append and upload objects. To install ossutil, see Install ossutil.

The following command appends content to the `exampleobject` object as a string.

ossutil api append-object --bucket examplebucket --key exampleobject --position 0 --body "hi oss"

For more information about this command, see append-object.

Related API operations

The preceding methods are based on API operations. If your program has high customization requirements, you can directly send REST API requests. To directly send REST API requests, you must manually write code to calculate signatures. For more information, see AppendObject.

FAQ

Are there any file type restrictions for append upload?

No. Append upload recognizes only binary streams and has no requirements for file types.

After I append multiple videos, why is the total size of the combined video equal to the sum of the individual video files, but the combined video contains only the content of the first appended video?

  • Cause

    Video files have a complex structure that includes metadata headers, an index, and other structured content. This content indicates information such as the total duration, codec, and frame rate of the video. When you directly append multiple video clips, the metadata of the original video is not automatically updated to accommodate the new content. As a result, the combined video file is just a concatenation of byte streams, and the combined video content cannot be correctly parsed.

  • Solution

    Use OSS with the video splicing feature of Intelligent Media Management (IMM) to merge videos. For more information, see Video splicing.

How do I convert a non-appendable file to an appendable file?

OSS does not support directly converting a non-appendable object to an appendable object. However, you can use the following method to perform the conversion:

  1. Use the AppendObject API operation to create a new, empty appendable object.

  2. Download the original object and read its content.

  3. Use the AppendObject API operation to append the content to the newly created object.

Important

The conversion process involves re-reading and re-uploading the content. After the conversion is complete, verify the availability of the object.