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:
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.
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:
- It is recommended to use file upload rather than file streams for local files.
- For large files, use multipart upload.
- The maximum upload size is 5GB.
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.
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:
- Creating a folder is essentially creating a zero-length object with a name ending in
/.- For nested folders, you only need to create the last level. For example, for
src1/src2/src3/, createsrc1/src2/src3/directly—you do not need to createsrc1/orsrc1/src2/.
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 |
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);
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.,
.xmlasapplication/xml;.htmlastext/html).
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.base64Md5to compute the MD5 value directly.
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.
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:
property1with valueproperty-value1, andproperty2with valueproperty-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.
Multipart upload is recommended in the following scenarios:
Benefits:
Implementation Steps:
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.getUploadIdreturns a unique Upload ID required for further operations.
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.setAttachMd5to 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,setAttachMd5is ignored.- Part numbers must be in the range 1 to 10000; otherwise, a 400 Bad Request error is returned.
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:
partEtagsshould contain the part numbers and ETags of all uploaded parts.- The parts do not need to be contiguous.
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.setOffsetandsetPartSizeto specify the offset and length for each part.
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);
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. UsegetNextPartNumberMarker()for pagination.- For tasks with more than 1,000 parts, use pagination to retrieve all parts.
do {
result = wosClient.listParts(request);
for(Multipart part : result.getMultipartList()){
// display part information
}
request.setPartNumberMarker(Integer.parseInt(result.getNextPartNumberMarker()));
} while (result.isTruncated());
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()andgetNextKeyMarker()/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());
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:
WosClient.createPostSignature to generate authentication parameters.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
policyandsignaturein the HTML form are taken from theWosClient.createPostSignatureresult.- You can download a demo HTML form as PostDemo.