com.obs.services.internal.UploadResumableClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of esdk-obs-java-bundle Show documentation
Show all versions of esdk-obs-java-bundle Show documentation
The HuaweiCloud OBS Bundle SDK for Java used for accessing Object Storage Service, this SDK bundle
includes third-party libraries and relocated to different namespaces
/**
* Copyright 2019 Huawei Technologies Co.,Ltd.
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of the
* License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.obs.services.internal;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import com.obs.log.ILogger;
import com.obs.log.LoggerBuilder;
import com.obs.services.AbstractClient;
import com.obs.services.exception.ObsException;
import com.obs.services.internal.io.ProgressInputStream;
import com.obs.services.internal.utils.SecureObjectInputStream;
import com.obs.services.internal.utils.ServiceUtils;
import com.obs.services.model.AbortMultipartUploadRequest;
import com.obs.services.model.CompleteMultipartUploadRequest;
import com.obs.services.model.CompleteMultipartUploadResult;
import com.obs.services.model.HeaderResponse;
import com.obs.services.model.InitiateMultipartUploadRequest;
import com.obs.services.model.InitiateMultipartUploadResult;
import com.obs.services.model.PartEtag;
import com.obs.services.model.UploadFileRequest;
import com.obs.services.model.UploadPartRequest;
import com.obs.services.model.UploadPartResult;
public class UploadResumableClient {
private static final ILogger log = LoggerBuilder.getLogger("com.obs.services.ObsClient");
private AbstractClient obsClient;
public UploadResumableClient(AbstractClient obsClient) {
this.obsClient = obsClient;
}
public CompleteMultipartUploadResult uploadFileResume(UploadFileRequest uploadFileRequest) {
ServiceUtils.assertParameterNotNull(uploadFileRequest, "UploadFileRequest is null");
ServiceUtils.assertParameterNotNull(uploadFileRequest.getBucketName(), "bucketName is null");
ServiceUtils.assertParameterNotNull2(uploadFileRequest.getObjectKey(), "objectKey is null");
ServiceUtils.assertParameterNotNull(uploadFileRequest.getUploadFile(), "uploadfile is null");
if (uploadFileRequest.isEnableCheckpoint()) {
if (!ServiceUtils.isValid(uploadFileRequest.getCheckpointFile())) {
uploadFileRequest.setCheckpointFile(uploadFileRequest.getUploadFile() + ".uploadFile_record");
}
}
if (uploadFileRequest.getCallback() != null) {
ServiceUtils.assertParameterNotNull(uploadFileRequest.getCallback().getCallbackUrl(),
"callbackUrl is null");
ServiceUtils.assertParameterNotNull(uploadFileRequest.getCallback().getCallbackBody(),
"callbackBody is null");
}
try {
return uploadFileCheckPoint(uploadFileRequest);
} catch (ServiceException e) {
throw ServiceUtils.changeFromServiceException(e);
} catch (Exception e) {
throw ServiceUtils.changeFromException(e);
}
}
protected void abortMultipartUploadSilent(String uploadId, UploadFileRequest uploadFileRequest) {
try {
abortMultipartUpload(uploadId, uploadFileRequest);
} catch (Exception e) {
if (log.isWarnEnabled()) {
log.warn("Abort multipart upload failed", e);
}
}
}
protected HeaderResponse abortMultipartUpload(String uploadId, UploadFileRequest uploadFileRequest) {
AbortMultipartUploadRequest request = new AbortMultipartUploadRequest(uploadFileRequest.getBucketName(),
uploadFileRequest.getObjectKey(), uploadId);
request.setRequesterPays(uploadFileRequest.isRequesterPays());
request.setUserHeaders(uploadFileRequest.getUserHeaders());
return this.obsClient.abortMultipartUpload(request);
}
private CompleteMultipartUploadResult uploadFileCheckPoint(UploadFileRequest uploadFileRequest) throws Exception {
UploadCheckPoint uploadCheckPoint = new UploadCheckPoint();
if (uploadFileRequest.isEnableCheckpoint()) {
prepareWithCheckpoint(uploadFileRequest, uploadCheckPoint);
} else {
prepare(uploadFileRequest, uploadCheckPoint);
}
// 开始上传
List partResults = uploadfile(uploadFileRequest, uploadCheckPoint);
// 有错误抛出异常,无异常则合并多段
for (PartResult partResult : partResults) {
if (partResult.isFailed() && partResult.getException() != null) {
// 未开启,取消多段
if (!uploadFileRequest.isEnableCheckpoint()) {
this.abortMultipartUploadSilent(uploadCheckPoint.uploadID, uploadFileRequest);
} else if (uploadCheckPoint.isAbort) {
this.abortMultipartUploadSilent(uploadCheckPoint.uploadID, uploadFileRequest);
if (uploadCheckPoint.isDeleteUploadRecordFile) {
ServiceUtils.deleteFileIgnoreException(uploadFileRequest.getCheckpointFile());
}
}
throw partResult.getException();
}
}
// 合并多段
CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(
uploadFileRequest.getBucketName(), uploadFileRequest.getObjectKey(), uploadCheckPoint.uploadID,
uploadCheckPoint.partEtags);
completeMultipartUploadRequest.setRequesterPays(uploadFileRequest.isRequesterPays());
completeMultipartUploadRequest.setEncodingType(uploadFileRequest.getEncodingType());
completeMultipartUploadRequest.setIsIgnorePort(uploadFileRequest.getIsIgnorePort());
completeMultipartUploadRequest.setCallback(uploadFileRequest.getCallback());
completeMultipartUploadRequest.setUserHeaders(uploadFileRequest.getUserHeaders());
try {
CompleteMultipartUploadResult result = this.obsClient
.completeMultipartUpload(completeMultipartUploadRequest);
if (uploadFileRequest.isEnableCheckpoint()) {
ServiceUtils.deleteFileIgnoreException(uploadFileRequest.getCheckpointFile());
}
return result;
} catch (ObsException e) {
if (!uploadFileRequest.isEnableCheckpoint()) {
this.abortMultipartUpload(uploadCheckPoint.uploadID, uploadFileRequest);
} else {
if (e.getResponseCode() >= 300 && e.getResponseCode() < 500 && e.getResponseCode() != 408) {
this.abortMultipartUploadSilent(uploadCheckPoint.uploadID, uploadFileRequest);
ServiceUtils.deleteFileIgnoreException(uploadFileRequest.getCheckpointFile());
}
}
throw e;
}
}
private void prepareWithCheckpoint(UploadFileRequest uploadFileRequest, UploadCheckPoint uploadCheckPoint)
throws IOException, Exception {
boolean needRecreate = false;
try {
uploadCheckPoint.load(uploadFileRequest.getCheckpointFile());
} catch (Exception e) {
needRecreate = true;
}
if (!needRecreate) {
if (!(uploadFileRequest.getBucketName().equals(uploadCheckPoint.bucketName)
&& uploadFileRequest.getObjectKey().equals(uploadCheckPoint.objectKey)
&& uploadFileRequest.getUploadFile().equals(uploadCheckPoint.uploadFile))) {
needRecreate = true;
} else if (!uploadCheckPoint.isValid(uploadFileRequest.getUploadFile())) {
needRecreate = true;
}
}
if (needRecreate) {
if (uploadCheckPoint.bucketName != null && uploadCheckPoint.objectKey != null
&& uploadCheckPoint.uploadID != null) {
this.abortMultipartUploadSilent(uploadCheckPoint.uploadID, uploadFileRequest);
}
ServiceUtils.deleteFileIgnoreException(uploadFileRequest.getCheckpointFile());
prepare(uploadFileRequest, uploadCheckPoint);
}
}
private List uploadfile(UploadFileRequest uploadFileRequest, UploadCheckPoint uploadCheckPoint)
throws Exception {
ArrayList pieceResults = new ArrayList();
ExecutorService executorService = Executors.newFixedThreadPool(uploadFileRequest.getTaskNum());
ArrayList> futures = new ArrayList>();
ProgressManager progressManager = null;
if (uploadFileRequest.getProgressListener() == null) {
for (int i = 0; i < uploadCheckPoint.uploadParts.size(); i++) {
UploadPart uploadPart = uploadCheckPoint.uploadParts.get(i);
if (uploadPart.isCompleted) {
PartResult pr = new PartResult(uploadPart.partNumber, uploadPart.offset, uploadPart.size);
pr.setFailed(false);
pieceResults.add(pr);
} else {
futures.add(executorService
.submit(new Mission(i, uploadCheckPoint, i, uploadFileRequest, this.obsClient)));
}
}
} else {
long transferredBytes = 0L;
List unfinishedUploadMissions = new LinkedList();
for (int i = 0; i < uploadCheckPoint.uploadParts.size(); i++) {
UploadPart uploadPart = uploadCheckPoint.uploadParts.get(i);
if (uploadPart.isCompleted) {
PartResult pr = new PartResult(uploadPart.partNumber, uploadPart.offset, uploadPart.size);
pr.setFailed(false);
pieceResults.add(pr);
transferredBytes += uploadPart.size;
} else {
unfinishedUploadMissions
.add(new Mission(i, uploadCheckPoint, i, uploadFileRequest, this.obsClient));
}
}
progressManager = new ConcurrentProgressManager(uploadCheckPoint.uploadFileStatus.size, transferredBytes,
uploadFileRequest.getProgressListener(), uploadFileRequest.getProgressInterval() > 0
? uploadFileRequest.getProgressInterval() : ObsConstraint.DEFAULT_PROGRESS_INTERVAL);
for (Mission mission : unfinishedUploadMissions) {
mission.setProgressManager(progressManager);
futures.add(executorService.submit(mission));
}
}
executorService.shutdown();
executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
for (Future future : futures) {
try {
PartResult tr = future.get();
pieceResults.add(tr);
} catch (ExecutionException e) {
if (!uploadFileRequest.isEnableCheckpoint()) {
this.abortMultipartUploadSilent(uploadCheckPoint.uploadID, uploadFileRequest);
}
throw e;
}
}
if (progressManager != null) {
progressManager.progressEnd();
}
return pieceResults;
}
static class Mission implements Callable {
private int id;
private UploadCheckPoint uploadCheckPoint;
private int partIndex;
private UploadFileRequest uploadFileRequest;
private AbstractClient obsClient;
private ProgressManager progressManager;
public Mission(int id, UploadCheckPoint uploadCheckPoint, int partIndex, UploadFileRequest uploadFileRequest,
AbstractClient obsClient) {
this.id = id;
this.uploadCheckPoint = uploadCheckPoint;
this.partIndex = partIndex;
this.uploadFileRequest = uploadFileRequest;
this.obsClient = obsClient;
}
@Override
public PartResult call() throws Exception {
PartResult tr = null;
UploadPart uploadPart = uploadCheckPoint.uploadParts.get(partIndex);
tr = new PartResult(partIndex + 1, uploadPart.offset, uploadPart.size);
if (!uploadCheckPoint.isAbort) {
InputStream input = null;
try {
UploadPartRequest uploadPartRequest = new UploadPartRequest();
uploadPartRequest.setBucketName(uploadFileRequest.getBucketName());
uploadPartRequest.setObjectKey(uploadFileRequest.getObjectKey());
uploadPartRequest.setUploadId(uploadCheckPoint.uploadID);
uploadPartRequest.setPartSize(uploadPart.size);
uploadPartRequest.setPartNumber(uploadPart.partNumber);
uploadPartRequest.setRequesterPays(uploadFileRequest.isRequesterPays());
uploadPartRequest.setUserHeaders(uploadFileRequest.getUserHeaders());
if (this.progressManager == null) {
uploadPartRequest.setFile(new File(uploadFileRequest.getUploadFile()));
uploadPartRequest.setOffset(uploadPart.offset);
} else {
input = new FileInputStream(uploadFileRequest.getUploadFile());
long offset = uploadPart.offset;
long skipByte = input.skip(offset);
if (offset < skipByte) {
log.error(String.format(
Locale.ROOT,
"The actual number of skipped bytes (%d) is less than expected (%d): ", skipByte,
offset));
}
// TODO no md5
uploadPartRequest.setInput(new ProgressInputStream(input, this.progressManager, false));
}
UploadPartResult result = obsClient.uploadPart(uploadPartRequest);
PartEtag partEtag = new PartEtag(result.getEtag(), result.getPartNumber());
uploadCheckPoint.update(partIndex, partEtag, true);
tr.setFailed(false);
if (uploadFileRequest.isEnableCheckpoint()) {
uploadCheckPoint.record(uploadFileRequest.getCheckpointFile());
}
} catch (ObsException e) {
if (e.getResponseCode() >= 300 && e.getResponseCode() < 500 && e.getResponseCode() != 408) {
uploadCheckPoint.isAbort = true;
}
if (e.getResponseCode() == 403) {
uploadCheckPoint.isDeleteUploadRecordFile = false;
}
// 有异常打印到日志文件
tr.setFailed(true);
tr.setException(e);
if (log.isErrorEnabled()) {
log.error(String.format(
Locale.ROOT,
"Task %d:%s upload part %d failed: ", id, "upload" + id, partIndex + 1),
e);
}
} catch (Exception e) {
tr.setFailed(true);
tr.setException(e);
if (log.isErrorEnabled()) {
log.error(String.format(
Locale.ROOT,
"Task %d:%s upload part %d failed: ", id, "upload" + id, partIndex + 1),
e);
}
} finally {
if (null != input) {
input.close();
}
}
} else {
tr.setFailed(true);
}
return tr;
}
public void setProgressManager(ProgressManager progressManager) {
this.progressManager = progressManager;
}
}
private void prepare(UploadFileRequest uploadFileRequest, UploadCheckPoint uploadCheckPoint) throws Exception {
uploadCheckPoint.uploadFile = uploadFileRequest.getUploadFile();
uploadCheckPoint.bucketName = uploadFileRequest.getBucketName();
uploadCheckPoint.objectKey = uploadFileRequest.getObjectKey();
uploadCheckPoint.uploadFileStatus = FileStatus.getFileStatus(uploadCheckPoint.uploadFile,
uploadFileRequest.isEnableCheckSum());
uploadCheckPoint.uploadParts = splitUploadFile(uploadCheckPoint.uploadFileStatus.size,
uploadFileRequest.getPartSize());
uploadCheckPoint.partEtags = new ArrayList();
InitiateMultipartUploadRequest initiateUploadRequest = new InitiateMultipartUploadRequest(
uploadFileRequest.getBucketName(), uploadFileRequest.getObjectKey());
initiateUploadRequest.setExtensionPermissionMap(uploadFileRequest.getExtensionPermissionMap());
initiateUploadRequest.setAcl(uploadFileRequest.getAcl());
initiateUploadRequest.setSuccessRedirectLocation(uploadFileRequest.getSuccessRedirectLocation());
initiateUploadRequest.setSseCHeader(uploadFileRequest.getSseCHeader());
initiateUploadRequest.setSseKmsHeader(uploadFileRequest.getSseKmsHeader());
initiateUploadRequest.setMetadata(uploadFileRequest.getObjectMetadata());
initiateUploadRequest.setRequesterPays(uploadFileRequest.isRequesterPays());
initiateUploadRequest.setEncodingType(uploadFileRequest.getEncodingType());
initiateUploadRequest.setIsEncodeHeaders(uploadFileRequest.isEncodeHeaders());
initiateUploadRequest.setUserHeaders(uploadFileRequest.getUserHeaders());
InitiateMultipartUploadResult initiateUploadResult = this.obsClient
.initiateMultipartUpload(initiateUploadRequest);
uploadCheckPoint.uploadID = initiateUploadResult.getUploadId();
if (uploadFileRequest.isEnableCheckpoint()) {
try {
uploadCheckPoint.record(uploadFileRequest.getCheckpointFile());
} catch (Exception e) {
this.abortMultipartUploadSilent(uploadCheckPoint.uploadID, uploadFileRequest);
throw e;
}
}
}
private ArrayList splitUploadFile(long size, long partSize) {
ArrayList parts = new ArrayList();
long partNum = size / partSize;
if (partNum >= 10000) {
partSize = size % 10000 == 0 ? size / 10000 : size / 10000 + 1;
partNum = size / partSize;
}
if (size % partSize > 0) {
partNum++;
}
if (partNum == 0) {
UploadPart part = new UploadPart();
part.partNumber = 1;
part.offset = 0;
part.size = 0;
part.isCompleted = false;
parts.add(part);
} else {
for (long i = 0; i < partNum; i++) {
UploadPart part = new UploadPart();
part.partNumber = (int) (i + 1);
part.offset = i * partSize;
part.size = partSize;
part.isCompleted = false;
parts.add(part);
}
if (size % partSize > 0) {
parts.get(parts.size() - 1).size = size % partSize;
}
}
return parts;
}
/**
* 断点续传上传所需类
*/
static class UploadCheckPoint implements Serializable {
private static final long serialVersionUID = 5564757792864743464L;
/**
* 从checkpoint文件中加载checkpoint数据
*
* @param checkPointFile
* @throws Exception
*/
public void load(String checkPointFile) throws Exception {
FileInputStream fileInput = null;
SecureObjectInputStream in = null;
try {
fileInput = new FileInputStream(checkPointFile);
in = new SecureObjectInputStream(fileInput);
UploadCheckPoint tmp = (UploadCheckPoint) in.readObject();
assign(tmp);
} finally {
if (null != in) {
try {
in.close();
} catch (IOException e) {
if (log.isWarnEnabled()) {
log.warn("close failed.", e);
}
}
}
if (null != fileInput) {
try {
fileInput.close();
} catch (IOException e) {
if (log.isWarnEnabled()) {
log.warn("close failed.", e);
}
}
}
}
}
/**
* 把checkpoint数据写到checkpoint文件
*
* @param checkPointFile
* @throws IOException
*/
public synchronized void record(String checkPointFile) throws IOException {
this.md5 = hashCode();
FileOutputStream fileOutput = null;
ObjectOutputStream outStream = null;
try {
fileOutput = new FileOutputStream(checkPointFile);
outStream = new ObjectOutputStream(fileOutput);
outStream.writeObject(this);
} finally {
if (null != outStream) {
try {
outStream.close();
} catch (IOException e) {
if (log.isWarnEnabled()) {
log.warn("close failed.", e);
}
}
}
if (null != fileOutput) {
try {
fileOutput.close();
} catch (IOException e) {
if (log.isWarnEnabled()) {
log.warn("close failed.", e);
}
}
}
}
}
/**
* 分块上传完成,更新状态
*
* @param partIndex
* @param partETag
* @param completed
*/
public synchronized void update(int partIndex, PartEtag partETag, boolean completed) {
partEtags.add(partETag);
uploadParts.get(partIndex).isCompleted = completed;
}
/**
* 判读本地文件与checkpoint中记录的信息是否相符合,校验一致性
*
* @param uploadFile
* @return boolean
* @throws IOException
*/
public boolean isValid(String uploadFile) throws IOException {
if (this.md5 != hashCode()) {
return false;
}
File upload = new File(uploadFile);
if (!this.uploadFile.equals(uploadFile) || this.uploadFileStatus.size != upload.length()
|| this.uploadFileStatus.lastModified != upload.lastModified()) {
return false;
}
if (this.uploadFileStatus.checkSum != null) {
try {
return this.uploadFileStatus.checkSum
.equals(ServiceUtils.toBase64(ServiceUtils.computeMD5Hash(new FileInputStream(upload))));
} catch (NoSuchAlgorithmException e) {
throw new ObsException("computeMD5Hash failed.", e);
}
}
return true;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((objectKey == null) ? 0 : objectKey.hashCode());
result = prime * result + ((bucketName == null) ? 0 : bucketName.hashCode());
result = prime * result + ((partEtags == null) ? 0 : partEtags.hashCode());
result = prime * result + ((uploadFile == null) ? 0 : uploadFile.hashCode());
result = prime * result + ((uploadFileStatus == null) ? 0 : uploadFileStatus.hashCode());
result = prime * result + ((uploadID == null) ? 0 : uploadID.hashCode());
result = prime * result + ((uploadParts == null) ? 0 : uploadParts.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
} else {
if (obj instanceof UploadCheckPoint) {
UploadCheckPoint uploadCheckPoint = (UploadCheckPoint) obj;
return uploadCheckPoint.hashCode() == obj.hashCode();
}
}
return false;
}
private void assign(UploadCheckPoint tmp) {
this.md5 = tmp.md5;
this.bucketName = tmp.bucketName;
this.uploadFile = tmp.uploadFile;
this.uploadFileStatus = tmp.uploadFileStatus;
this.objectKey = tmp.objectKey;
this.uploadID = tmp.uploadID;
this.uploadParts = tmp.uploadParts;
this.partEtags = tmp.partEtags;
}
public int md5;
public String uploadFile;
public FileStatus uploadFileStatus;
public String bucketName;
public String objectKey;
public String uploadID;
public ArrayList uploadParts;
public ArrayList partEtags;
public transient volatile boolean isAbort = false;
public transient volatile boolean isDeleteUploadRecordFile = true;
}
static class FileStatus implements Serializable {
private static final long serialVersionUID = -3135754191745936521L;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((checkSum == null) ? 0 : checkSum.hashCode());
result = prime * result + (int) (lastModified ^ (lastModified >>> 32));
result = prime * result + (int) (size ^ (size >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
} else {
if (obj instanceof FileStatus) {
FileStatus fileStatus = (FileStatus) obj;
return fileStatus.hashCode() == obj.hashCode();
}
}
return false;
}
public static FileStatus getFileStatus(String uploadFile, boolean checkSum) throws IOException {
FileStatus fileStatus = new FileStatus();
File file = new File(uploadFile);
fileStatus.size = file.length();
fileStatus.lastModified = file.lastModified();
if (checkSum) {
try {
fileStatus.checkSum = ServiceUtils.toBase64(ServiceUtils.computeMD5Hash(new FileInputStream(file)));
} catch (NoSuchAlgorithmException e) {
throw new ObsException("computeMD5Hash failed.", e);
}
}
return fileStatus;
}
public long size; // 文件大小
public long lastModified; // 文件最后修改时间
public String checkSum; // 文件checkSum
}
static class UploadPart implements Serializable {
private static final long serialVersionUID = 751520598820222785L;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (isCompleted ? 1 : 0);
result = prime * result + partNumber;
result = prime * result + (int) (offset ^ (offset >>> 32));
result = prime * result + (int) (size ^ (size >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
} else {
if (obj instanceof UploadPart) {
UploadPart uploadPart = (UploadPart) obj;
return uploadPart.hashCode() == obj.hashCode();
}
}
return false;
}
public int partNumber; // 分片序号
public long offset; // 分片在文件中的偏移量
public long size; // 分片大小
public boolean isCompleted; // 该分片上传是否完成
}
static class PartResult {
public PartResult(int partNumber, long offset, long length) {
this.partNumber = partNumber;
this.offset = offset;
this.length = length;
}
public int getpartNumber() {
return partNumber;
}
public void setpartNumber(int partNumber) {
this.partNumber = partNumber;
}
public long getOffset() {
return offset;
}
public void setOffset(long offset) {
this.offset = offset;
}
public long getLength() {
return length;
}
public void setLength(long length) {
this.length = length;
}
public boolean isFailed() {
return isFailed;
}
public void setFailed(boolean isFailed) {
this.isFailed = isFailed;
}
public Exception getException() {
return exception;
}
public void setException(Exception exception) {
this.exception = exception;
}
private int partNumber; // 分片序号
private long offset; // 分片在文件中的偏移
private long length; // 分片长度
private boolean isFailed; // 分片上传是否失败
private Exception exception; // 分片上传异常
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy