Upload files
In BOS, the basic data unit for user operations is an object. An object consists of a key, metadata, and data. The key is the object’s name, the metadata provides a user-defined description as a set of name-value pairs, and the data is the content of the object.
The BOS Java SDK provides a rich set of file upload APIs, and files can be uploaded in the following ways:
- Simple upload
- Append upload
- Multipart upload
- Resumable upload
Simple upload
In simple upload scenarios, BOS supports uploading objects in the form of specified files, data streams, binary strings, and character strings. Please refer to the following code or Simple Upload Demo.
1public void PutObject(BosClient client, String bucketName, String objectKey, byte[] byte1, String string1){
2 // Get specified file
3 File file = new File("/path/to/file.zip");
4 // Obtain data stream
5 InputStream inputStream = new FileInputStream("/path/to/test.zip");
6
7 // Upload object as a file
8 PutObjectResponse putObjectFromFileResponse = client.putObject(bucketName, objectKey, file);
9 // Upload an object in the form of a data stream
10 PutObjectResponse putObjectResponseFromInputStream = client.putObject(bucketName, objectKey, inputStream);
11 // Upload object as binary string
12 PutObjectResponse putObjectResponseFromByte = client.putObject(bucketName, objectKey, byte1);
13 // Upload object in string form
14 PutObjectResponse putObjectResponseFromString = client.putObject(bucketName, objectKey, string1);
15 // Create an empty directory. The objectKey must end with a forward slash, such as test/
16 // The BOS console will, by default, display objects ending with a forward slash (/) as file directories
17 PutObjectResponse putObjectResponseFromString = client.putObject(bucketName, objectKey, "");
18
19 // Print ETag
20 System.out.println(putObjectFromFileResponse.getETag());
21}
Files are uploaded to BOS as objects. The PutObject function supports uploading objects with a size of up to 5 GB. Upon successful processing of a PutObject request, BOS returns the object's ETag in the response header as its unique identifier.
Set file meta information
Object metadata refers to the attributes of files provided by users when uploading to BOS. It is mainly divided into two categories: standard HTTP attribute settings (HTTP headers) and user-defined metadata.
- Set Http header of object
The BOS Java SDK essentially interacts with the backend HTTP API, allowing users to customize the HTTP headers of the object when uploading files. The following describes some commonly used HTTP headers:
| Name | Description | Default value |
|---|---|---|
| Content-MD5 | File data verification: After setting, BOS will enable file content MD5 verification, compare the MD5 you provide with the MD5 of the file, and throw an error if they are inconsistent | None |
| Content-Type | File MIME: This defines the file type and web page encoding, determining how the browser reads the file. If unspecified, BOS generates it based on the file's extension. If the file lacks an extension, a default value will be applied. | application/octet-stream |
| Content-Disposition | Indicate how the MIME user agent displays the attached file, whether to open or download it, and the file name | None |
| Content-Length | The length of the uploaded file. If it exceeds the length of the stream/file, it will be truncated; if it is insufficient, it will be the actual value | Stream/file duration |
| Expires | Cache expiration time | None |
| Cache-Control | Specify the caching behavior of the web page when the object is downloaded | None |
| x-bce-content-crc32 | The CRC value (cyclic redundancy check code) of uploaded object | None |
Reference code is as follows:
1//Initialize the upload input stream
2ObjectMetadata meta = new ObjectMetadata();
3 // Set ContentLength size
4meta.setContentLength(1000);
5 // Set ContentType
6meta.setContentType("application/json");
7 //Set cache-control
8meta.setCacheControl("no-cache");
9 // Set x-bce-content-crc32. The file’s CRC32 check code must be calculated by the user themselves. The format example is as follows
10meta.setxBceCrc("0x74E947D0");
11client.putObject(bucketName, objectKey, content, meta);
- User-defined meta information
BOS supports user-defined metadata for describing objects. Example usage is shown in the following code:
1// Set the value of custom metadata name to my-data
2meta.addUserMetadata("name", "my-data");
3
4 // Upload Object
5client.putObject(bucketName, objectKey, content, meta);
Prompt:
- In the above code, the user has customized a metadata with the name "name" and value "my-data".
- When users download this object, this metadata can also be obtained.
- An object may have multiple similar parameters, but the total size of all user meta must not exceed 2KB.
Set storage class when uploading an object
BOS supports standard storage, infrequent access storage, and cold storage. Uploading an object and storing it as an infrequent access storage class is achieved by specifying the StorageClass. The parameters corresponding to the three storage classes are as follows:
| Storage class | Parameters |
|---|---|
| Standard storage | STANDARD |
| Infrequent access storage | STANDARD_IA |
| Cold storage | COLD |
Taking infrequent access storage as an example, the code is as follows:
1public void putObjectStorageClass(){
2 PutObjectRequest request = new PutObjectRequest(bucketName, key, file);
3 request.withStorageClass(BosClient.STORAGE_CLASS_STANDARD_IA);
4 client.putObject(request);
5}
Append upload
Objects created using the simple upload method described above are all of a standard type and do not support append writes. This limitation can be inconvenient in scenarios where frequent data overwriting occurs, such as log files, video surveillance, and live video streaming.
To address this, Baidu AI Cloud Object Storage (BOS) specifically supports the AppendObject method, which allows files to be uploaded in an append-write fashion. Objects created through the AppendObject operation are categorized as Appendable Objects, enabling data to be appended to them. The size limit for AppendObject files is 0–5 GB.
The sample code for uploading via the AppendObject method is as follows, or refer to Append Upload Demo.
1public void AppendObject(BosClient client, String bucketName, String objectKey, byte[] byte1, String string1) {
2 // Get specified file
3 File file = new File("/path/to/file.zip");
4 // Obtain data stream
5 InputStream inputStream = new FileInputStream("/path/to/test.zip");
6 // Upload object as a file
7 AppendObjectResponse appendObjectFromFileResponse = client.appendObject(bucketName, objectKey, file);
8 // Upload an object in the form of a data stream
9 AppendObjectResponse appendObjectResponseFromInputStream = client.appendObject(bucketName, objectKey, inputStream);
10 // Upload object as binary string
11 AppendObjectResponse appendObjectResponseFromByte = client.appendObject(bucketName, objectKey, byte1);
12 // Upload object in string form
13 AppendObjectResponse appendObjectResponseFromString = client.appendObject(bucketName, objectKey, string1);
14 // Print ETag
15 System.out.println(appendObjectFromFileResponse.getETag());
16 //Print NextAppendOffset
17 System.out.println(appendObjectFromFileResponse.getNextAppendOffset());
18 // Print ContentMd5
19 System.out.println(appendObjectFromFileResponse.getContentMd5());
20 //Example of append upload, need to add the position of the next append write in the request
21 Long nextAppendOffset = appendObjectFromFileResponse.getNextAppendOffset();
22 AppendObjectRequest appendObjectFromFileRequest = new AppendObjectRequest(bucketName,objectKey,file);
23 appendObjectFromFileRequest.setOffset(nextAppendOffset);
24 AppendObjectResponse appendObjectFromFileResponse = client.appendObject(appendObjectFromFileRequest);
25 }
Note:
- For append upload, the position for appending must be specified; otherwise, the already written data will be overwritten.
- Concurrent operations are not supported. If there is indeed a need for multi-client writing, you need to maintain the append position by yourself to avoid conflicts
Multipart upload
Besides uploading files to BOS using simple upload and append upload modes, BOS also supports another option—Multipart Upload. Users can use Multipart Upload mode in various scenarios, including but not limited to the ones below:
- When resumable uploads are required.
- When uploading files larger than 5GB.
- When the connection to the BOS server is frequently interrupted due to unstable network conditions.
- Enable streaming file uploads.
- The file size cannot be determined before uploading.
The following will introduce the implementation of Multipart Upload step by step. Suppose there is a file with the local path /path/to/file.zip. Since the file is large, it will be transmitted to BOS in parts. Or refer to Multipart Upload Demo
Initialize multipart upload
Use initiateMultipartUpload method to initialize a multipart upload event:
1// Initiate Multipart Upload
2InitiateMultipartUploadRequest initiateMultipartUploadRequest =
3 new InitiateMultipartUploadRequest(bucketName, objectKey);
4InitiateMultipartUploadResponse initiateMultipartUploadResponse =
5 client.initiateMultipartUpload(initiateMultipartUploadRequest);
6
7 // Print UploadId
8System.out.println("UploadId: " + initiateMultipartUploadResponse.getUploadId());
The return result of initiateMultipartUpload contains UploadId, which is the unique identifier for distinguishing multipart upload events, and we will use it in subsequent operations.
- Initialization for uploading infrequent access storage class objects
Initialize a multipart upload event for infrequent access storage:
1public void putMultiUploadStorageClass(){
2 InitiateMultipartUploadRequest iniReq = new InitiateMultipartUploadRequest(bucketName, key);
3 iniReq.withStorageClass(BosClient.STORAGE_CLASS_STANDARD_IA);
4 client.initiateMultipartUpload(iniReq);
5}
- Initialization for uploading a cold storage class object
Initialize a multipart upload event for infrequent access storage:
1public void putMultiUploadStorageClass(){
2 InitiateMultipartUploadRequest iniReq = new InitiateMultipartUploadRequest(bucketName, key);
3 iniReq.withStorageClass(BosClient.STORAGE_CLASS_COLD);
4 client.initiateMultipartUpload(iniReq);
5}
Upload parts
The file is then uploaded in multiple parts.
1// Set each part to 5MB
2final long partSize = 1024 * 1024 * 5L;
3
4File partFile = new File("/path/to/file.zip");
5
6 // Calculate the count of parts
7int partCount = (int) (partFile.length() / partSize);
8if (partFile.length() % partSize != 0){
9 partCount++;
10}
11
12 // Create a list to save the ETag and PartNumber of each uploaded part
13List<PartETag> partETags = new ArrayList<PartETag>();
14
15for(int i = 0; i < partCount; i++){
16 // Get file stream
17 FileInputStream fis = new FileInputStream(partFile);
18
19 //Jump to the beginning of each part
20 long skipBytes = partSize * i;
21 fis.skip(skipBytes);
22
23 // Calculate the size of each part
24 long size = partSize < partFile.length() - skipBytes ?
25 partSize : partFile.length() - skipBytes;
26
27 // Create UploadPartRequest to upload parts
28 UploadPartRequest uploadPartRequest = new UploadPartRequest();
29 uploadPartRequest.setBucketName(bucketName);
30 uploadPartRequest.setKey(objectKey);
31 uploadPartRequest.setUploadId(initiateMultipartUploadResponse.getUploadId());
32 uploadPartRequest.setInputStream(fis);
33 uploadPartRequest.setPartSize(size);
34 uploadPartRequest.setPartNumber(i + 1);
35 UploadPartResponse uploadPartResponse = client.uploadPart(uploadPartRequest);
36
37 // Save the returned PartETag to the List.
38 partETags.add(uploadPartResponse.getPartETag());
39
40 // Close the file
41 fis.close();
42}
The core of the above code is to call the UploadPart method to upload each part, but the following points should be noted:
- The UploadPart method requires that the size of each part, except the last one, must be greater than or equal to 100KB. However, the Upload Part interface does not immediately validate the Part size; validation occurs only during completing multipart upload.
- To ensure no errors during network transmission, it is recommended to use the Content-MD5 value returned by BOS for each part after
UploadPartto verify the correctness of the uploaded part data. When all part data is combined into one Object, it no longer contains the MD5 value. - The part number must be within the range of 1 to 10,000. If this limit is exceeded, BOS will return an InvalidArgument error code.
- For each uploaded part, the stream must be positioned at the beginning of the respective part.
- After each Part upload, the return result of BOS will include a
PartETagobject, which is a combination of the uploaded block's ETag and block number (PartNumber). It will be used in subsequent steps to complete the multipart upload, so it must be saved. Generally speaking, thesePartETagobjects will be saved in a List.
Complete multipart upload
Complete the multipart upload as shown in the following code:
1CompleteMultipartUploadRequest completeMultipartUploadRequest =
2 new CompleteMultipartUploadRequest(bucketName, objectKey, initiateMultipartUploadResponse.getUploadId(), partETags);
3
4 // Complete multipart upload
5CompleteMultipartUploadResponse completeMultipartUploadResponse =
6 client.completeMultipartUpload(completeMultipartUploadRequest);
7
8 // Print Object's ETag
9System.out.println(completeMultipartUploadResponse.getETag());
The partETags in the above code is the list of partETag saved in the second step. After BOS receives the part list submitted by the user, it will verify the validity of each data Part one by one. Once all data parts are validated, BOS will assemble the data parts into a complete Object.
Cancel multipart upload event
Users can cancel multipart uploads by using the abortMultipartUpload method.
1AbortMultipartUploadRequest abortMultipartUploadRequest =
2 new AbortMultipartUploadRequest(bucketName, objectKey, uploadId);
3
4 // Cancel multipart upload
5client.abortMultipartUpload(abortMultipartUploadRequest);
Retrieve unfinished multipart upload event
Users can obtain the unfinished multipart upload events in the bucket by the listMultipartUploads method.
1ListMultipartUploadsRequest listMultipartUploadsRequest =
2 new ListMultipartUploadsRequest(bucketName);
3 // Retrieve all upload events within the bucket
4ListMultipartUploadsResponse listing = client.listMultipartUploads(listMultipartUploadsRequest);
5
6 // Traverse all upload events
7for (MultipartUploadSummary multipartUpload : listing.getMultipartUploads()) {
8 System.out.println("Key: " + multipartUpload.getKey() + " UploadId: " + multipartUpload.getUploadId());
9}
Note:
- By default, if the number of multipart upload events in a bucket surpasses 1,000, only 1,000 records will be returned. In such cases, the IsTruncated value in the response will be True, and the NextKeyMarker will indicate the starting point for the next query.
- To retrieve more multipart upload events, you can utilize the KeyMarker parameter for batch reading.
Get all uploaded part information
Users can obtain all uploaded parts in an upload event by the listParts method.
1ListPartsRequest listPartsRequest = new ListPartsRequest(bucketName, objectKey, uploadId);
2
3 // Retrieve all uploaded part information
4ListPartsResponse partListing = client.listParts(listPartsRequest);
5
6 // Traverse all parts
7for (PartSummary part : partListing.getParts()) {
8 System.out.println("PartNumber: " + part.getPartNumber() + " ETag: " + part.getETag());
9}
If you need to view the storage class of an object, use the following code:
1public void listPartsStorageClass(){
2 ListResponse listPartsResponse = client.listParts(bucketName, key, uploadId);
3 String storageClass = listPartsResponse.getStorageClass();
4}
Note:
- By default, if the number of multipart upload events in a bucket surpasses 1,000, only 1,000 records will be returned. In such cases, the IsTruncated value in the response will be True, and the NextPartNumberMarker will indicate the starting point for the next query.
- To fetch additional multipart upload events, you can utilize the PartNumberMarker parameter for batch reading.
Encapsulate multipart upload
In the Java SDK, Bos provides users with the putSuperObjectFromFile API, which encapsulates the three methods involved in multipart upload: initiateMultipartUpload, UploadPart and completeMultipartUpload. Users only need to call this API to complete the multipart upload.
1File file = new File("/path/to/file.zip");
2PutSuperObjectRequest request = new PutSuperObjectRequest(bucketName, objectKey, file);
3bosClient.putSuperObjectFromFile(request);
The parameters of PutSuperObjectRequest include:
| Parameters | Description |
|---|---|
| chunkSize | Part size: The default is 5 MB, and it cannot be less than 100 KB |
| nThreads | Number of threads in the thread pool for multipart upload: The default is equal to the number of CPU cores |
| isSuperObjectUploadCanced | Cancel multipart upload or not |
| File | Upload files |
If uploading a large file takes too long and the user wishes to end the multipart upload, they can call the cancel() method in PutSuperObjectRequest to set isSuperObjectUploadCanceled to true, thereby canceling the multipart upload operation.
Resumable upload
When users upload large files to BOS, if the network is unstable or the program crashes, the entire upload will fail, and the parts that have been uploaded before the failure will also be invalid. Users have to start over. This not only wastes resources but also often fails to complete the upload after multiple retries in an unstable network environment. Based on the above scenarios, BOS provides the capability of resumable upload:
- In a generally stable network, it is recommended to use the three-step upload method, dividing the object into 5 MB blocks, refer to [Multipart Upload](#Multipart upload).
- If your network condition is very poor, it is recommended to use the appendObject method for resumable upload, appending small data (256 KB) each time, refer to [Append Upload](#Append upload).
Tips
- Resumable upload is an encapsulation and enhancement of multipart upload, implemented using multipart upload;
- For large files or poor network environments, it is recommended to use multipart upload;
Fetch and upload
The following code retrieves resources from a specified URL and stores them in a designated bucket. This process requires the requester to have write permissions for the bucket. Only one object can be fetched at a time, and the user can specify a custom object name. For details, refer to the FetchObject API.
1String fetchurl = "bj.bcebos.com/sourbucket/sourceobject";
2FetchObjectRequest req = new FetchObjectRequest(bucketname, objectname, fetchurl);
3req.setReferer("www.referer.com");
4bosClient.fetchObject(req);
The parameters of FetchObjectRequest include:
| Parameters | Description |
|---|---|
| source | Source address of the fetched file |
| mode | Fetch mode: Supports two modes, asynchronous fetch (async) and synchronous fetch (sync), and the optional values are MODE_SYNC and MODE_ASYNC |
| storageClass | Storage class: Supports standard storage (STANDARD), infrequent access storage (STANDARD_IA), cold storage (COLD), and archive storage (ARCHIVE). The default storage class is STANDARD |
| callbackAddress | Fetch result callback address. If the asynchronous fetch mode is selected, results will be pushed here upon completion |
| referer | Referer header to be passed through during fetch at origin server |
| userAgent | User-Agent header to be passed through during fetch at origin server |
Obtain upload progress
Supports providing real-time upload progress updates during the upload process. It currently supports four APIs: PutObject, AppendObject, UploadPart, and PutSuperObjectFromFile. The progress upload API accepts optional custom data.
The Java SDK defines upload progress callback APIs that allow users to define actions needed during upload, such as updating the API.
1public interface ProgressCallback<T> {
2 void onProgress(long currentSize, long totalSize, T data);
3}
- PutObject example code:
1BosProgressCallback<Object> callback = new BosProgressCallback<Object>() {
2 @Override
3 public void onProgress(long currentSize, long totalSize, Object data) {
4 // Print upload progress
5 System.out.println("put " + currentSize + "/" + totalSize);
6 }
7};
8 // If you need to use custom data in onProgress
9callback.setData(obj);
10PutObjectRequest request = new PutObjectRequest(bucketName, objectKey, file);
11request.setProgressCallback(callback);
12client.putObject(request);
- AppendObject example code:
1BosProgressCallback<Object> callback = new BosProgressCallback<Object>() {
2 @Override
3 public void onProgress(long currentSize, long totalSize, Object data) {
4 System.out.println("put " + currentSize + "/" + totalSize);
5 }
6};
7 // If you need to use custom data in onProgress
8callback.setData(obj);
9AppendObjectRequest request = new AppendObjectRequest(bucketName, objectKey, file);
10request.setProgressCallback(callback);
11AppendObjectResponse response = client.appendObject(request);
12Long nextAppendOffset = response.getNextAppendOffset();
- UploadPart example code:
1BosProgressCallback<Object> callback = new BosProgressCallback<Object>() {
2 @Override
3 public void onProgress(long currentSize, long totalSize, Object data) {
4 System.out.println("put " + currentSize + "/" + totalSize);
5 }
6};
7 // If you need to use custom data in onProgress
8callback.setData(obj);
9UploadPartRequest request = new UploadPartRequest();
10request.setBucketName(bucketName);
11request.setKey(objectKey);
12request.setUploadId(id);
13request.setInputStream(inputStream);
14request.setPartSize(size);
15request.setPartNumber(i);
16request.setProgressCallback(callback);
17client.uploadPart(request);
- PutSuperObjectFromFile example code:
1BosProgressCallback<Object> callback = new BosProgressCallback<Object>() {
2 @Override
3 public void onProgress(long currentSize, long totalSize, Object data) {
4 System.out.println("put " + currentSize + "/" + totalSize);
5 }
6};
7 // If you need to use custom data in onProgress
8callback.setData(obj);
9PutSuperObjectRequest request = new PutSuperObjectRequest(bucketName, objectKey, file);
10request.setProgressCallback(callback);
11client.putSuperObjectFromFile(request);
Single-link rate limit
Baidu AI Cloud Object Storage (BOS) applies bandwidth limits per bucket. When the user's upload or download bandwidth usage reaches the threshold, the error code RequestRateLimitExceeded will be triggered.
To ensure normal service usage, BOS implements traffic control during upload and download processes, ensuring that large traffic services do not impact other applications.
The upload API supports setting the specified rate limit value. The value range of the rate limit value is 819200~838860800 in bit/s, that is, 100KB/s~100MB/s. The rate limit value must be a number. BOS will limit the rate of this request according to the specified rate limit value. When the rate limit value is not within this range or is illegal, it will return the error code 400.
- PutObject example code:
1PutObjectRequest request = new PutObjectRequest(bucketName, objectKey, file);
2 // Specify the upload speed limit as 819,200 bit/s, i.e., 100 KB/s
3request.setTrafficLimitBitPS(819200);
4client.putObject(request);
- AppendObject example code:
1AppendObjectRequest request = new AppendObjectRequest(bucketName, objectKey, file);
2 // Specify the upload speed limit as 819,200 bit/s, i.e., 100 KB/s
3request.setTrafficLimitBitPS(819200);
4AppendObjectResponse response = client.appendObject(request);
5Long nextAppendOffset = response.getNextAppendOffset();
- PutSuperObjectFromFile example code:
1PutSuperObjectRequest request = new PutSuperObjectRequest(bucketName, objectKey, file);
2 // Specify the upload speed limit as 819,200 bit/s, i.e., 100 KB/s
3request.setTrafficLimitBitPS(819200);
4client.putSuperObjectFromFile(request);
Upload callback
The API is used by BOS to provide synchronous callbacks to the application server when uploading file (object). The application server refers to the server corresponding to the callback address provided by the user. For specific descriptions, please refer to Upload Callback. The usage of the Java SDK server upload callback is as follows:
- PutObject example code:
1PutObjectRequest putObjectRequest = new PutObjectRequest("bucketName","objectKey", file);
2String callBackUrl = "[\""+"https://localhost:8080/callback" +"\"]";
3String enCodeUrl = "";
4try {
5 enCodeUrl = Base64.getEncoder().encodeToString(callBackUrl.getBytes(DEFAULT_ENCODING));
6}catch (Exception e){
7 e.printStackTrace();
8}
9putObjectRequest.setxBceProcess("callback/callback,u_" + enCodeUrl);
10PutObjectResponse putObjectResponse = client.putObject(putObjectRequest);
11System.out.println(putObjectResponse.getCallback().getResult());
