优秀的编程知识分享平台

网站首页 > 技术文章 正文

对象存储oos如何实现分片上传(对象存储能上传文件夹吗)

nanyue 2025-07-09 16:27:53 技术文章 3 ℃

直接上干货,分片上传需要完成3步。

1.初始化分片上传。当此步骤成功完成之后,在存储桶(bucket)里便能搜到该文件,大小为 0 字节。需留意的是,应尽量避免对同一文件进行多次初始化操作。较为妥当的做法是,先终止前一次的初始化分片上传流程,再进行第二次的初始化分片上传工作。

private static String initialMultipartUpload(AmazonS3 oosClient) {
try {
// 必须设置BucketName和ObjectName
InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(BUCKET_NAME, OBJECT_NAME);
// 设置存储类型,默认是标准存储,可不配置
request.setStorageClass(StorageClass.Standard);
// 设置元数据信息,例如设置数据的存放位置,可不配置
ObjectMetadata objectMetadata = new ObjectMetadata();
CtyunBucketDataLocation dataLocation = new CtyunBucketDataLocation();
ArrayList<String> location = new ArrayList<>();
// 设置数据存档的位置为青岛
location.add("QingDao");
dataLocation.setDataRegions(location);
// Allowed 允许调度 | NotAllowed 不允许调度, 可不配置
dataLocation.setStragegy(CtyunBucketDataLocation.CtyunBucketDataScheduleStrategy.Allowed);
objectMetadata.setDataLocation(dataLocation);
request.setObjectMetadata(objectMetadata);
InitiateMultipartUploadResult res = oosClient.initiateMultipartUpload(request);
String uploadID = res.getUploadId();
System.out.println("initialMultipartUpload success!" +
"\n" + "uploadID: " + uploadID);
return uploadID;
} catch (AmazonServiceException se) {
System.out.println(se.toString());
} catch (AmazonClientException ce) {
System.out.println(ce.getMessage());
}
return null;
}

2.上传分片。在初始化分片上传时,系统会返回一个上传标识(uploadId)。凭借此标识,便能够向存储桶内的大小为 0 字节的文件追加内容。需特别注意的是,每一个分片的大小必须大于 5MB,不过最后一个分片不受此限制。上传了多少内容,此时便能够通过对象存储下载相应字节数的内容。值得一提的是,此时存储桶里的文件在显示上依然为 0 字节,然而在下载时,文件已经包含了上传的内容。

* @param oosClient 初始化后的AmazonS3客户端
* @param uploadId 调用initiateMultipartUpload接口返回的uploadId
* @param currentPartNumber 当前上传的是第几片
* @param currentPartSize 当前上传片的大小 单位Byte
* @param parts 所有分片成功上传后返回的eTag值
* @param partNum 需要上传的分片总数
* @param offset 当前上传片的偏置 单位Byte
*/
private static void uploadPart(AmazonS3 oosClient, String uploadId, int currentPartNumber, long currentPartSize,
List<PartETag> parts, long partNum, long offset) {
try {
boolean isLastPart = currentPartNumber == partNum;
UploadPartRequest request = new UploadPartRequest().withUploadId(uploadId);
// 设置需要分片上传的文件
// 注意无需自行分片,直接设置需要分片上传的文件即可
request.setFile(UPLOAD_FILE);
// 设置BucketName
request.setBucketName(BUCKET_NAME);
// 设置ObjectName
request.setKey(OBJECT_NAME);
// 设置上传的是第几片
request.setPartNumber(currentPartNumber);
// 设置上传片的大小
request.setPartSize(currentPartSize);
// 如果不是第一个片,则需设置片的偏置
if (currentPartNumber != 1) {
request.setFileOffset(offset);
}
// 设置是否是最后一个片
request.setLastPart(isLastPart);
UploadPartResult res = oosClient.uploadPart(request);
System.out.println("uploadPart " + currentPartNumber + " success!");
String eTag = res.getPartETag().getETag();
System.out.println("eTag: " + eTag);
PartETag e = new PartETag(currentPartNumber, eTag);
parts.add(e);
System.out.println("The " + currentPartNumber + " part-> size: " + request.getPartSize() + " offset: " + request.getFileOffset());
} catch (AmazonServiceException se) {
System.out.println(se.toString());
} catch (AmazonClientException ce) {
System.out.println(ce.getMessage());
}
}

3.合并分片上传。此操作会依据上传标识(uploadId),结束该文件的分片上传通道,此后将无法继续向该文件追加内容。但在存储桶中,文件的大小已变实际大小。需要提醒的是,倘若你需要不定期地向文件追加内容,那么就不要进行合并分片操作。

* @param oosClient 初始化后的AmazonS3客户端
* @param uploadId 调用initiateMultipartUpload接口返回的uploadId
* @param parts 所有分片成功上传后返回的eTag值
*/
private static void completeMultipartUpload(AmazonS3 oosClient, String uploadId, List<PartETag> parts) {
try {
// 必须配置BucketName,ObjectName,初始化分片的uploadId和各个分片上传成功后返回的eTag值
CompleteMultipartUploadRequest request = new CompleteMultipartUploadRequest(BUCKET_NAME, OBJECT_NAME, uploadId, parts);
CompleteMultipartUploadResult result = oosClient.completeMultipartUpload(request);
System.out.println("complete multipart upload success!" +
"\n" + "location: " + result.getLocation());
System.out.printf("bucket:%s,obj:%s,etag:%s%n", result.getBucketName(), result.getKey(), result.getETag());
} catch (AmazonServiceException se) {
System.out.println(se.toString());
} catch (AmazonClientException ce) {
System.out.println(ce.getMessage());
}
}

4.主函数和Client

public static void main(String[] args) {
AmazonS3 client = getClient();
// 初始化分片上传
String uploadId = initialMultipartUpload(client);
// 终止分片上传
//abortMultipartUpload(client, uploadId);
// 分片大小(5MB)
long partSize = 5 * 1024 * 1024;
// 总分片数量
long PartNum = 3;
// 存储每个分片的 ETag
List<PartETag> partETags = new ArrayList<>();
// 上传第一个分片
long firstPartOffset = 0;
uploadPart(client, uploadId, 1, partSize, partETags, PartNum, firstPartOffset);
// 上传第二个分片
long secondPartOffset = partSize;
uploadPart(client, uploadId, 2, partSize, partETags, PartNum, secondPartOffset);
// 上传第三个分片
long thirdPartOffset = 2 * partSize;
long thirdPartSize = UPLOAD_FILE.length() - thirdPartOffset;
uploadPart(client, uploadId, 3, thirdPartSize, partETags, PartNum, thirdPartOffset);
// 完成分片上传
completeMultipartUpload(client, uploadId, partETags);
}
private static AmazonS3 getClient() {
ClientConfiguration cc = new ClientConfiguration();
cc.setMaxErrorRetry(3);
cc.setConnectionTimeout(30000);
cc.setSocketTimeout(30000);
cc.setProtocol(Protocol.HTTP);

//设置path-style方式,如oos-cn.ctyunapi.cn/bucket.example
//S3ClientOptions options = new S3ClientOptions();
//options.setPathStyleAccess(true);

//支持的最大并发连接数
cc.setMaxConnections(100);
// 是否使用v4
System.setProperty(SDKGlobalConfiguration.ENABLE_S3_SIGV4_SYSTEM_PROPERTY, "true");
AmazonS3 client = new AmazonS3Client(new AWSCredentials() {
@Override
public String getAWSAccessKeyId() {
return TestConfig.OOS_ACCESS_KEY;
}
@Override
public String getAWSSecretKey() {
return TestConfig.OOS_SECRET_KEY;
}
}, cc);
client.setEndpoint(TestConfig.OOS_ENDPOINT);
//设置path-style方式,如oos-cn.ctyunapi.cn/bucket.example
//client.setS3ClientOptions(options);
return client;
}

oos-java-sdk下载地址:
https://www.ctyun.cn/document/10026693/10026825

最近发表
标签列表