更新时间:2025-06-16 GMT+08:00
Java
分段上传Java语言的示例代码,如下所示:
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2019-2022. All rights reserved.
*/
package com.huaweicloud.vod;
import com.huaweicloud.sdk.core.auth.BasicCredentials;
import com.huaweicloud.sdk.core.auth.ICredential;
import com.huaweicloud.sdk.core.exception.ConnectionException;
import com.huaweicloud.sdk.core.exception.RequestTimeoutException;
import com.huaweicloud.sdk.core.exception.ServiceResponseException;
import com.huaweicloud.sdk.vod.v1.VodClient;
import com.huaweicloud.sdk.vod.v1.model.ConfirmAssetUploadReq;
import com.huaweicloud.sdk.vod.v1.model.ConfirmAssetUploadRequest;
import com.huaweicloud.sdk.vod.v1.model.ConfirmAssetUploadResponse;
import com.huaweicloud.sdk.vod.v1.model.CreateAssetByFileUploadReq;
import com.huaweicloud.sdk.vod.v1.model.CreateAssetByFileUploadRequest;
import com.huaweicloud.sdk.vod.v1.model.CreateAssetByFileUploadResponse;
import com.huaweicloud.sdk.vod.v1.model.ShowAssetTempAuthorityRequest;
import com.huaweicloud.sdk.vod.v1.model.ShowAssetTempAuthorityResponse;
import com.huaweicloud.sdk.vod.v1.region.VodRegion;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.TimeZone;
/**
* 分段上传示例
*/
public class PartUploadDemo {
// 设置缓冲区大小,每次读取文件分段的大小,根据情况自行设定
public static final int bufferSize = 1024 * 1024; // 1MB
// 区域
public static final String REGION_NORTH4 = "cn-north-4";
public static final String REGION_NORTH1 = "cn-north-1";
public static final String REGION_EAST2 = "cn-east-2";
// ak/sk
private static final String AK = "";
private static final String SK = "";
public static void main(String[] args) {
// 本地要上传的媒资路径
String filePath = "";
PartUploadDemo uploadDemo = new PartUploadDemo();
// 上传媒资文件
uploadDemo.uploadPartFile(filePath);
}
/**
* 分段上传
* @param filePath 上传文件的本地路径
*/
public void uploadPartFile(String filePath) {
// 校验一下文件路径和文件
File file = validFile(filePath);
try {
String fileName = file.getName();
// 此处仅以MP4文件示例,其他格式可参考官网说明
String fileType = "MP4";
String fileContentType = "video/mp4";
// FileInfo fileInfo = new FileInfo(filePath, file);
// 1.初始化鉴权并获取vodClient
VodClient vodClient = this.createVodClient();
System.out.println("开始创建媒资:" + file.getName());
// 2.创建点播媒资
CreateAssetByFileUploadReq reqbody = this.buildFileUploadReq(fileName, fileType, null, null);
CreateAssetByFileUploadResponse assetResponse = this.createAssetByFileUpload(vodClient, reqbody);
// 3.获取初始化上传任务授权
ShowAssetTempAuthorityResponse initAuthResponse = this.initPartUploadAuthority(vodClient, assetResponse, fileContentType);
// 4.初始化上传任务
String uploadId = this.initPartUpload(initAuthResponse.getSignStr(), fileContentType);
// 文件分段计数
int partNumber = 1;
// 缓冲区
byte[] fileByte = new byte[bufferSize];
// 记录读取的长度
int readLength = 0;
// 7.读取文件内容, 循环5-6步上传所有分段
FileInputStream fis = new FileInputStream(file);
// MD5
MessageDigest md = MessageDigest.getInstance("MD5");
while ((readLength = fis.read(fileByte)) > 0) {
// 读取的长度小于缓冲区长度,复制有效长度内数据,用于最后一段
if(readLength < bufferSize) {
fileByte = Arrays.copyOf(fileByte, readLength);
}
// 先md5,再base64 encode
byte[] digest = md.digest(fileByte);
String contentMd5 = new String(Base64.encodeBase64(digest));
System.out.println("该文件第"+(partNumber)+"段MD5为: " + contentMd5);
// 5.获取上传分段的授权
ShowAssetTempAuthorityResponse partUploadAuthorityResponse = this.getPartUploadAuthority(vodClient, fileContentType, assetResponse, contentMd5, uploadId, partNumber);
// 6.上传分段
this.uploadPartFile(partUploadAuthorityResponse.getSignStr(), fileByte, contentMd5);
// 段号自增
partNumber++;
}
fis.close();
// 8.获取已上传分段的授权
ShowAssetTempAuthorityResponse listPartUploadAuthorityResponse = this.listUploadedPartAuthority(vodClient, assetResponse, uploadId);
// 9.获取已上传的分段
String partInfo = this.listUploadedPart(listPartUploadAuthorityResponse.getSignStr());
// 10.获取合并段授权
ShowAssetTempAuthorityResponse mergePartUploadAuthorityResponse = this.mergeUploadedPartAuthority(vodClient, assetResponse, uploadId);
// 11.合并上传分段
this.mergeUploadedPart(mergePartUploadAuthorityResponse.getSignStr(), partInfo);
// 12.确认媒资上传
this.confirmUploaded(vodClient, assetResponse);
System.out.println("创建媒资结束 assetId:" + assetResponse.getAssetId());
} catch (ServiceResponseException e) {
e.printStackTrace();
System.out.println(String.valueOf(e.getHttpStatusCode()));
System.out.println(e.getRequestId());
System.out.println(e.getErrorCode());
System.out.println(e.getErrorMsg());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 校验文件路径和文件
* @param filePath
*/
private File validFile(String filePath){
if (StringUtils.isEmpty(filePath)) {
throw new RuntimeException("输入的文件路径为空!");
}
File file = new File(filePath);
if (!file.exists()) {
throw new RuntimeException("文件不存在!");
} else if (file.isDirectory()) {
try {
throw new RuntimeException(file.getCanonicalPath() + "这是一个目录!");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return file;
}
/**
* 1.构建鉴权
* @return
*/
public VodClient createVodClient(){
ICredential auth = new BasicCredentials()
.withAk(AK)
.withSk(SK)
;
return VodClient.newBuilder()
.withCredential(auth)
.withRegion(VodRegion.valueOf(REGION_NORTH4))
.build();
}
/**
* 2.创建媒资
* @param client
* @param reqbody
* @return
*/
public CreateAssetByFileUploadResponse createAssetByFileUpload(VodClient client, CreateAssetByFileUploadReq reqbody){
System.out.println("createAssetByFileUpload start");
CreateAssetByFileUploadRequest request = new CreateAssetByFileUploadRequest();
// 设置 X-Sdk-Date参数,ak/sk认证必传
request.setXSdkDate(getXSdkDate());
// 设置上传参数
request.withBody(reqbody);
// 调用创建媒资
CreateAssetByFileUploadResponse response = client.createAssetByFileUpload(request);
System.out.println("createAssetByFileUpload end; createAssetResponse:" + response.toString());
return response;
}
/**
* 构建创建媒资请求参数
* @param fileName
* @param videoName
* @param title
* @return
*/
public CreateAssetByFileUploadReq buildFileUploadReq(String fileName, String videoType, String videoName, String title){
CreateAssetByFileUploadReq req = new CreateAssetByFileUploadReq();
req.withVideoName(StringUtils.isNotEmpty(videoName) ? videoName : fileName);
req.withTitle(StringUtils.isNotEmpty(title) ? title : fileName);
// 设置媒资类型
req.withVideoType(videoType);
return req;
}
/**
* 取 X-Sdk-Date 参数,当前UTC时间, 时间格式 yyyyHHddTHHmmssZ 例如: 20240312T092514Z
* @return
*/
public String getXSdkDate(){
TimeZone zone = TimeZone.getTimeZone("UTC");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'");
return LocalDateTime.now(zone.toZoneId()).format(formatter);
}
/**
* 3.获取初始化上传任务授权
* @param client
* @param assetResponse
*/
public ShowAssetTempAuthorityResponse initPartUploadAuthority(VodClient client, CreateAssetByFileUploadResponse assetResponse, String fileContentType){
System.out.println("获取初始化上传任务授权 initPartUploadAuthority start");
ShowAssetTempAuthorityRequest request = new ShowAssetTempAuthorityRequest();
request.setXSdkDate(getXSdkDate());
// 设置参数
request.withHttpVerb("POST");
request.withBucket(assetResponse.getTarget().getBucket());
request.withObjectKey(assetResponse.getTarget().getObject());
request.withContentType(fileContentType);
// 发送初始化请求
ShowAssetTempAuthorityResponse response = client.showAssetTempAuthority(request);
System.out.println("获取初始化上传任务授权 initPartUploadAuthority end; response: " + response.toString());
return response;
}
/**
* 4.初始化分段上传
* @param signStr
* @param contentType
* @return
*/
public String initPartUpload(String signStr, String contentType) throws DocumentException {
System.out.println("初始化分段上传 initPartUpload start");
HttpResponse response = HttpRequest.post(signStr).header("Content-type",contentType).execute();
System.out.println(response.body());
Document document = DocumentHelper.parseText(response.body());
Element root = document.getRootElement();
Element u = root.element("UploadId");
System.out.println("初始化分段上传 initPartUpload end; UploadId:" + u.getText());
return u.getText();
}
/**
* 5.获取分段上传授权
* @param client
* @param fileContentType
* @param assetResponse
* @param contentMd5
* @param uploadId
* @param partNumber
* @return
*/
public ShowAssetTempAuthorityResponse getPartUploadAuthority(VodClient client, String fileContentType, CreateAssetByFileUploadResponse assetResponse, String contentMd5, String uploadId, int partNumber) {
System.out.println("获取分段上传授权 getPartUploadAuthority start; partNumber: " + partNumber);
ShowAssetTempAuthorityRequest request = new ShowAssetTempAuthorityRequest();
request.setXSdkDate(getXSdkDate());
request.withHttpVerb("PUT");
request.withBucket(assetResponse.getTarget().getBucket());
request.withObjectKey(assetResponse.getTarget().getObject());
request.withContentType(fileContentType);
request.withContentMd5(contentMd5);
request.withUploadId(uploadId);
request.withPartNumber(partNumber);
ShowAssetTempAuthorityResponse response = client.showAssetTempAuthority(request);
System.out.println("获取分段上传授权 getPartUploadAuthority end; partNumber: " + partNumber + "; response" + response.toString());
return response;
}
/**
* 6.上传分段
* @param signStr
* @param fileByte
* @param contentMd5
*/
public void uploadPartFile(String signStr, byte[] fileByte, String contentMd5) {
System.out.println("上传分段 uploadPartFile start");
HttpResponse response = HttpRequest.put(signStr)
// 此处contentMd5不需要转义
.header("Content-MD5", contentMd5)
.header("Content-Type", "application/octet-stream")
.body(fileByte).execute();
System.out.println(response.toString());
if (response.getStatus() != 200) {
throw new RuntimeException("上传分段 uploadPartFile end; 上传失败!");
}
System.out.println("上传分段 uploadPartFile end");
}
/**
* 8.获取列举已上传段的授权
* @param client
* @param assetResponse
* @param uploadId
* @return
*/
public ShowAssetTempAuthorityResponse listUploadedPartAuthority(VodClient client, CreateAssetByFileUploadResponse assetResponse, String uploadId){
System.out.println("获取列举已上传段的授权 listUploadedPartAuthority start");
ShowAssetTempAuthorityRequest request = new ShowAssetTempAuthorityRequest();
request.setXSdkDate(getXSdkDate());
request.withHttpVerb("GET");
request.withBucket(assetResponse.getTarget().getBucket());
request.withObjectKey(assetResponse.getTarget().getObject());
request.withUploadId(uploadId);
ShowAssetTempAuthorityResponse response = client.showAssetTempAuthority(request);
System.out.println("获取列举已上传段的授权 listUploadedPartAuthority end; response: " + response.toString());
return response;
}
/**
* 9.查询已上传的分段
* @param signStr
* @return
*/
public String listUploadedPart(String signStr) throws DocumentException {
System.out.println("查询已上传的分段 listUploadedPart start");
int partNumberMarker = 0;
Element mergerRoot = DocumentHelper.createElement("CompleteMultipartUpload");
while(true) {
//列举分段
HttpResponse response = HttpRequest.get(signStr + "&part-number-marker=" + partNumberMarker).execute();
System.out.println("listUploadedPartResponse:" + response.body());
Document responseDocument = DocumentHelper.parseText(response.body());
Element rootResponse = responseDocument.getRootElement();
List<Element> elementsResponse = rootResponse.elements("Part");
Element partNumberMarkerElement = rootResponse.element("NextPartNumberMarker");
for (Element e : elementsResponse) {
Element te = DocumentHelper.createElement("Part");
te.add(e.element("PartNumber").createCopy());
te.add(e.element("ETag").createCopy());
mergerRoot.add(te);
}
partNumberMarker = Integer.valueOf(partNumberMarkerElement.getText());
if(partNumberMarker % 1000 != 0) {
break;
}
}
System.out.println(mergerRoot.asXML());
System.out.println("查询已上传的分段 listUploadedPart end");
return mergerRoot.asXML();
}
/**
* 10.获取合并段授权
* @param client
* @param assetResponse
* @param uploadId
* @return
*/
public ShowAssetTempAuthorityResponse mergeUploadedPartAuthority(VodClient client, CreateAssetByFileUploadResponse assetResponse, String uploadId) {
System.out.println("获取合并段授权 mergeUploadedPartAuthority start");
ShowAssetTempAuthorityRequest request = new ShowAssetTempAuthorityRequest();
request.setXSdkDate(getXSdkDate());
request.withHttpVerb("POST");
request.withBucket(assetResponse.getTarget().getBucket());
request.withObjectKey(assetResponse.getTarget().getObject());
request.withUploadId(uploadId);
ShowAssetTempAuthorityResponse response = client.showAssetTempAuthority(request);
System.out.println("获取合并段授权 mergeUploadedPartAuthority end; response: " + response.toString());
return response;
}
/**
* 11.合并分段
*/
public void mergeUploadedPart(String signStr, String partInfo) {
System.out.println("合并分段 mergeUploadedPart start");
// 请求消息头中增加“Content-Type”,值设置为“application/xml”。
HttpResponse response = HttpRequest.post(signStr)
.header("Content-Type","application/xml")
.body(partInfo)
.execute();
System.out.println(response.toString());
if (response.getStatus() != 200) {
throw new RuntimeException("合并分段 mergeUploadedPart end; 合并段失败!");
}
System.out.println("合并分段 mergeUploadedPart end");
}
/**
* 12.确认上传完成
*/
public void confirmUploaded(VodClient client, CreateAssetByFileUploadResponse assetResponse) {
System.out.println("确认上传完成 confirmUploaded start");
ConfirmAssetUploadRequest request = new ConfirmAssetUploadRequest();
request.setXSdkDate(getXSdkDate());
ConfirmAssetUploadReq body = new ConfirmAssetUploadReq();
body.withStatus(ConfirmAssetUploadReq.StatusEnum.fromValue("CREATED"));
body.withAssetId(assetResponse.getAssetId());
request.withBody(body);
ConfirmAssetUploadResponse response = client.confirmAssetUpload(request);
System.out.println("上传完成,assetId:" + response.toString());
}
}
父主题: 分段上传代码示例