Upload

Last update:2025-08-18 15:54:16

In CDNetworks Object Storage, the fundamental unit of data that users interact with is the object. The Java SDK provides a variety of object upload interfaces, enabling you to upload objects in the following ways:

  • Stream upload
  • File upload
  • Multipart upload
  • Form-based upload

The SDK supports uploading objects ranging from 0KB up to 5GB in size. For stream uploads and file uploads, the content size must not exceed 5GB. For larger files, it is recommended to use multipart upload, where each part must not exceed 5GB. Form-based uploads allow you to upload objects via browser-based HTML forms.

If you grant anonymous read access when uploading an object, the object will be publicly accessible via a direct link after the upload succeeds. The object link format is: https://bucket-name.domain/folder-path/object-name. If the object is stored in the root directory of the bucket, the folder path can be omitted from the link.


1. Stream Upload

Stream uploads use java.io.InputStream as the data source for the object. You can upload your data stream using WosClient.putObject. The following code demonstrates how to upload data using streams:

// Upload a string (byte array)
String endPoint = "https://your-endpoint";
String ak = "*** Provide your Access Key ***";
String sk = "*** Provide your Secret Key ***";
// Create WosClient instance
WosClient wosClient = new WosClient(ak, sk, endPoint, regionName);

String content = "Hello WOS";
wosClient.putObject("bucketname", "objectname", new ByteArrayInputStream(content.getBytes()));

// Upload a network stream
InputStream inputStream = new URL("http://www.a.com").openStream();
wosClient.putObject("bucketname", "objectname", inputStream);

// Upload a file stream
FileInputStream fis = new FileInputStream(new File("localfile"));  // Specify the full file path
wosClient.putObject("bucketname", "objectname", fis);

Notes:

  1. It is recommended to use file upload rather than file streams for local files.
  2. For large files, use multipart upload.
  3. The maximum upload size is 5GB.

2. File Upload

File uploads use a local file as the data source for the object. The following code demonstrates how to upload a file:

String endPoint = "https://your-endpoint";
String ak = "*** Provide your Access Key ***";
String sk = "*** Provide your Secret Key ***";
// Create WosClient instance
WosClient wosClient = new WosClient(ak, sk, endPoint, regionName);

wosClient.putObject("bucketname", "objectname", new File("localfile")); // Specify the full file path

Note: The maximum upload size is 5GB.


3. Creating Folders

CDNetworks Object Storage does not natively support folders; only objects are stored within a bucket. Creating a folder is essentially creating a zero-length object whose name ends with a /. These objects behave like any other object and can be downloaded or deleted, but the console will display them as folders.

String endPoint = "https://your-endpoint";
String ak = "*** Provide your Access Key ***";
String sk = "*** Provide your Secret Key ***";
// Create WosClient instance
WosClient wosClient = new WosClient(ak, sk, endPoint, regionName);

final String keySuffixWithSlash = "parent_directory/";
wosClient.putObject("bucketname", keySuffixWithSlash, new ByteArrayInputStream(new byte[0]));

// Create an object within the folder
wosClient.putObject("bucketname", keySuffixWithSlash + "objectname", new ByteArrayInputStream("Hello WOS".getBytes()));

Notes:

  1. Creating a folder is essentially creating a zero-length object with a name ending in /.
  2. For nested folders, you only need to create the last level. For example, for src1/src2/src3/, create src1/src2/src3/ directly—you do not need to create src1/ or src1/src2/.

4. Setting Object Metadata

You can set object metadata when uploading objects. Metadata includes object length, MIME type, MD5 value (for validation), storage class, and custom user metadata. Metadata can be set for all upload methods (stream, file, multipart) and when copying objects.

The following table describes each field:

Name Description Default Value
Content Length
(Content-Length)
The length of the uploaded object; must not exceed the source file/stream length. Excess content is truncated. Actual stream or file length
MIME Type
(Content-Type)
Specifies object/file type or web page encoding; determines how browsers handle the object. application/octet-stream
MD5 Value
(Content-MD5)
The object’s MD5 hash (Base64-encoded), used by the server to verify data integrity. None
Storage Class The object’s storage class. Different classes can optimize for performance and cost.
Defaults to the same as the bucket’s storage class.
None
Custom User Metadata Defines custom properties for personalized object management. None

Setting Content-Length

You can set the object length using ObjectMetadata.setContentLength. Example:

ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(1024 * 1024L); // 1MB
wosClient.putObject("bucketname", "objectname", new File("localfile"), metadata);

Setting MIME Type

You can set the MIME type using ObjectMetadata.setContentType. Example:

ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType("image/jpeg");
wosClient.putObject("bucketname", "objectname.jpg", new File("localimage.jpg"), metadata);

Note: If you do not set the MIME type, the SDK will automatically infer it based on the object’s file extension (e.g., .xml as application/xml; .html as text/html).

Setting MD5 Value

Use ObjectMetadata.setContentMd5 to specify the object’s MD5 value. Example:

ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentMd5("your md5 which should be encoded by base64");
wosClient.putObject("bucketname", "objectname", new File("localimage.jpg"), metadata);

Notes:

  • The MD5 value must be Base64-encoded.
  • The server will compare the provided MD5 value with the computed MD5 of the uploaded data. If they do not match, the upload will fail with a HTTP 400 error.
  • If you do not set the MD5 value, the server will skip this check.
  • You can use WosClient.base64Md5 to compute the MD5 value directly.

Setting Storage Class

Set the storage class with ObjectMetadata.setObjectStorageClass. Example:

ObjectMetadata metadata = new ObjectMetadata();
metadata.setObjectStorageClass(StorageClassEnum.ia); // Set to Infrequent Access
wosClient.putObject("bucketname", "objectname", new File("localfile"), metadata);

Notes:

  • If not specified, the object’s storage class defaults to the bucket’s class.
  • There are three storage classes, with the same meaning as the bucket’s storage class.
  • Archive storage objects must be restored before downloading.

Setting Custom Metadata

Set custom metadata using ObjectMetadata.addUserMetadata. Example:

ObjectMetadata metadata = new ObjectMetadata();
metadata.addUserMetadata("property1", "property-value1");
metadata.getMetadata().put("property2", "property-value2");
wosClient.putObject("bucketname", "objectname", new File("localfile"), metadata);

Notes:

  • The above example sets two custom metadata fields: property1 with value property-value1, and property2 with value property-value2.
  • Multiple metadata fields can be set; the total size must not exceed 8KB.
  • You can retrieve custom metadata using WosClient.getObjectMetadata.
  • When downloading objects using WosClient.getObject, custom metadata will also be returned.

5. Multipart Upload

Multipart upload is recommended in the following scenarios:

  • Uploading files larger than 100MB
  • Unstable networks or limited bandwidth
  • Unknown file size at upload time

Benefits:

  • Parallel uploads increase throughput
  • Supports resumable uploads if the network disconnects
  • Tasks can be paused or resumed as needed—there is no automatic lifecycle, so tasks must be actively canceled
  • The total size does not need to be known in advance

Implementation Steps:

  1. Initialize (WosClient.initiateMultipartUpload)
  2. Upload parts sequentially or in parallel (WosClient.uploadPart)
  3. Complete (WosClient.completeMultipartUpload) or abort (WosClient.abortMultipartUpload)

Initialization

You must first initiate a multipart upload and set its parameters. This will return an Upload ID, which uniquely identifies the multipart upload. The Upload ID is required for subsequent operations such as aborting, querying, and listing parts.

InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest("bucketname", "objectname");
ObjectMetadata metadata = new ObjectMetadata();
metadata.addUserMetadata("property", "property-value");
metadata.setContentType("text/plain");
request.setMetadata(metadata);
InitiateMultipartUploadResult result = wosClient.initiateMultipartUpload(request);

String uploadId = result.getUploadId();
System.out.println("\t" + uploadId);

Notes:

  • Use InitiateMultipartUploadRequest to specify the object name and bucket.
  • You can set MIME type, storage class, custom user metadata, etc.
  • InitiateMultipartUploadResult.getUploadId returns a unique Upload ID required for further operations.

Uploading Parts

After initialization, you can upload parts using the object name and Upload ID. Each part is uniquely identified by a Part Number (between 1 and 10000). The part number determines not only identification, but also the ordering during merge. Uploading a part with an existing number will overwrite the previous part. Except for the last part, each part’s size must be between 100KB-5GB; the last part can be 0-5GB. Parts can be uploaded in any order and from different processes or machines. The server will assemble them in order by part number.

List<PartEtag> partEtags = new ArrayList<PartEtag>();
// Upload first part
UploadPartRequest request = new UploadPartRequest("bucketname", "objectname");
request.setUploadId(uploadId);
request.setPartNumber(1);
request.setFile(new File("localfile"));
request.setPartSize(5 * 1024 * 1024L);
UploadPartResult result = wosClient.uploadPart(request);
partEtags.add(new PartEtag(result.getEtag(), result.getPartNumber()));

// Upload second part
request = new UploadPartRequest("bucketname", "objectname");
request.setUploadId(uploadId);
request.setPartNumber(2);
request.setFile(new File("localfile"));
request.setOffset(5 * 1024 * 1024L);
request.setPartSize(5 * 1024 * 1024L);
result = wosClient.uploadPart(request);
partEtags.add(new PartEtag(result.getEtag(), result.getPartNumber()));

Notes:

  • Except for the last part, all parts must be larger than 100KB. The size is only validated when completing the upload.
  • The server returns the ETag (MD5 hash) for each part.
  • For integrity, set UploadPartRequest.setAttachMd5 to true to let the SDK compute and set the MD5 for each part (works for local files only). WOS will compare this with the received data.
  • You can also manually set UploadPartRequest.setContentMd5; if set, setAttachMd5 is ignored.
  • Part numbers must be in the range 1 to 10000; otherwise, a 400 Bad Request error is returned.

Completing the Multipart Upload

Once all parts are uploaded, call the complete API to assemble them in the final object. You must provide the complete, ordered list of part numbers and ETags. The server verifies all parts before merging them.

List<PartEtag> partEtags = new ArrayList<PartEtag>();
// Populate partEtags with the part numbers and ETags returned from uploads

CompleteMultipartUploadRequest completeRequest = new CompleteMultipartUploadRequest("bucketname", "objectname", uploadId, partEtags);

wosClient.completeMultipartUpload(completeRequest);

Notes:

  • partEtags should contain the part numbers and ETags of all uploaded parts.
  • The parts do not need to be contiguous.

Concurrent Multipart Upload

The main advantage of multipart upload is more reliable and faster large file uploads. The following example demonstrates concurrent uploads:

// Initialization omitted for brevity
ExecutorService executorService = Executors.newFixedThreadPool(20);
final File largeFile = new File("localfile");

long partSize = 100 * 1024 * 1024L;
long fileSize = largeFile.length();
long partCount = fileSize % partSize == 0 ? fileSize / partSize : fileSize / partSize + 1;
final List<PartEtag> partEtags = Collections.synchronizedList(new ArrayList<PartEtag>());

for (int i = 0; i < partCount; i++) {
    final long offset = i * partSize;
    final long currPartSize = (i + 1 == partCount) ? fileSize - offset : partSize;
    final int partNumber = i + 1;
    executorService.execute(() -> {
        UploadPartRequest uploadPartRequest = new UploadPartRequest();
        uploadPartRequest.setBucketName(bucketName);
        uploadPartRequest.setObjectKey(objectKey);
        uploadPartRequest.setUploadId(uploadId);
        uploadPartRequest.setFile(largeFile);
        uploadPartRequest.setPartSize(currPartSize);
        uploadPartRequest.setOffset(offset);
        uploadPartRequest.setPartNumber(partNumber);

        try {
            UploadPartResult uploadPartResult = wosClient.uploadPart(uploadPartRequest);
            System.out.println("Part#" + partNumber + " done\n");
            partEtags.add(new PartEtag(uploadPartResult.getEtag(), uploadPartResult.getPartNumber()));
        } catch (WosException e) {
            e.printStackTrace();
        }
    });
}
executorService.shutdown();
while (!executorService.isTerminated()) {
    executorService.awaitTermination(5, TimeUnit.SECONDS);
}
// Merge parts
CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(bucketName, objectKey, uploadId, partEtags);
wosClient.completeMultipartUpload(completeMultipartUploadRequest);

Note: For multipart upload, use UploadPartRequest.setOffset and setPartSize to specify the offset and length for each part.

Aborting Multipart Upload

Multipart upload tasks can be aborted. Once canceled, their Upload ID becomes invalid and all uploaded parts for that upload are deleted.

To save storage space, you can clear incomplete or failed uploads by aborting multipart tasks:

AbortMultipartUploadRequest request = new AbortMultipartUploadRequest("bucketname", "objectname", uploadId);
wosClient.abortMultipartUpload(request);

Listing Uploaded Parts

You can list all uploaded parts of a given multipart task using WosClient.listParts.

ListPartsRequest request = new ListPartsRequest("bucketname", "objectname");
request.setUploadId(uploadId);
ListPartsResult result = wosClient.listParts(request);

for (Multipart part : result.getMultipartList()) {
    System.out.println("\t" + part.getPartNumber());   // Part number
    System.out.println("\t" + part.getSize());         // Part size
    System.out.println("\t" + part.getEtag());         // Part ETag
    System.out.println("\t" + part.getLastModified()); // Last modified
}

Notes:

  • Up to 1,000 parts are returned per request. If more parts exist, ListPartsResult.isTruncated() returns true. Use getNextPartNumberMarker() for pagination.
  • For tasks with more than 1,000 parts, use pagination to retrieve all parts.

Listing All Parts (with Pagination)

do {
    result = wosClient.listParts(request);
    for(Multipart part : result.getMultipartList()){
        // display part information
    }
    request.setPartNumberMarker(Integer.parseInt(result.getNextPartNumberMarker()));
} while (result.isTruncated());

Listing Multipart Upload Tasks

Use WosClient.listMultipartUploads to list all ongoing multipart upload tasks:

ListMultipartUploadsRequest request = new ListMultipartUploadsRequest("bucketname");
MultipartUploadListing result = wosClient.listMultipartUploads(request);
for (MultipartUpload upload : result.getMultipartTaskList()) {
    System.out.println("\t" + upload.getUploadId());
    System.out.println("\t" + upload.getObjectKey());
    System.out.println("\t" + upload.getInitiatedDate());
}

Notes:

  • Up to 1,000 uploads are returned per request. Use isTruncated() and getNextKeyMarker()/getNextUploadIdMarker() to paginate if needed.

Paginated Listing Example:

do {
    result = wosClient.listMultipartUploads(request);
    for (MultipartUpload upload : result.getMultipartTaskList()) {
        // display upload info
    }
    request.setKeyMarker(result.getNextKeyMarker());
    request.setUploadIdMarker(result.getNextUploadIdMarker());
} while (result.isTruncated());

6. Form-Based Upload

Form-based upload allows you to upload an object to a bucket using an HTML form. The maximum object size is 5GB.

You can use WosClient.createPostSignature to generate the required form upload parameters. For details, see PostObjectSample.

Steps:

  • Call WosClient.createPostSignature to generate authentication parameters.
  • Prepare an HTML form.
  • Fill in the form fields using the generated parameters.
  • Select a file locally and submit the form for upload.

Parameters generated by WosClient.createPostSignature:

  • policy (for the policy field in the form)
  • signature (for the signature field in the form)

Example of generating form parameters:

PostSignatureRequest request = new PostSignatureRequest();
Map<String, Object> formParams = new HashMap<String, Object>();
formParams.put("x-wos-acl", "public-read");             // Set object ACL
formParams.put("content-type", "text/plain");           // Set MIME type

request.setFormParams(formParams);
request.setExpires(3600);                               // Validity in seconds
PostSignatureResponse response = wosClient.createPostSignature(request);

formParams.put("key", objectKey);
formParams.put("policy", response.getPolicy());
formParams.put("accesskeyid", ak);
formParams.put("x-wos-credential", response.getCredential());
formParams.put("x-wos-algorithm", response.getAlgorithm());
formParams.put("bucket", bucketName);
formParams.put("x-wos-date", response.getDate());
formParams.put("x-wos-signature", response.getSignature());

System.out.println("\t" + response.getPolicy());
System.out.println("\t" + response.getSignature());

Sample HTML Form:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<form action="http://bucketname.your-endpoint/" method="post" enctype="multipart/form-data">
Object key
<input type="text" name="key" value="objectname" />
<p>
ACL
<input type="text" name="x-wos-acl" value="public-read" />
<p>
Content-Type
<input type="text" name="content-type" value="text/plain" />
<p>
<input type="hidden" name="policy" value="*** Provide your policy ***" />
<input type="hidden" name="AccessKeyId" value="*** Provide your access key ***"/>
<input type="hidden" name="signature" value="*** Provide your signature ***"/>
<input name="file" type="file" />
<input name="submit" value="Upload" type="submit" />
</form>
</body>
</html>

Notes:

  • The values for policy and signature in the HTML form are taken from the WosClient.createPostSignature result.
  • You can download a demo HTML form as PostDemo.
Is the content of this document helpful to you?
Yes
I have suggestion
Submitted successfully! Thank you very much for your feedback, we will continue to strive to do better!