0
点赞
收藏
分享

微信扫一扫

阿里云OSS 分块上传的代码整理


废话不多说,把代码贴出来。

package com.changba.erp.utils;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.CompleteMultipartUploadRequest;
import com.aliyun.oss.model.InitiateMultipartUploadRequest;
import com.aliyun.oss.model.InitiateMultipartUploadResult;
import com.aliyun.oss.model.ListPartsRequest;
import com.aliyun.oss.model.PartETag;
import com.aliyun.oss.model.PartListing;
import com.aliyun.oss.model.PartSummary;
import com.aliyun.oss.model.UploadPartRequest;
import com.aliyun.oss.model.UploadPartResult;

public class AliyunOSSUpload implements Runnable {
private MultipartFile localFile;
private long startPos;

private long partSize;
private int partNumber;
private String uploadId;
private static String key;
private static String bucketName;

// 新建一个List保存每个分块上传后的ETag和PartNumber
protected static List<PartETag> partETags = Collections.synchronizedList(new ArrayList<PartETag>());

private static Logger logger = LoggerFactory.getLogger(FileUploader.class);

protected static OSSClient client = null;

/**
* 创建构造方法
*
* @param localFile
* 要上传的文件
* @param startPos
* 每个文件块的开始
* @param partSize
* @param partNumber
* @param uploadId
* 作为块的标识
* @param key
* 上传到OSS后的文件名
*/
public AliyunOSSUpload(MultipartFile localFile, long startPos, long partSize, int partNumber, String uploadId, String key , String bucketName) {
this.localFile = localFile;
this.startPos = startPos;
this.partSize = partSize;
this.partNumber = partNumber;
this.uploadId = uploadId;
AliyunOSSUpload.key = key;
AliyunOSSUpload.bucketName = bucketName;
}

/**
* 分块上传核心方法(将文件分成按照每个5M分成N个块,并加入到一个list集合中)
*/
@Override
public void run() {
InputStream instream = null;
try {
// 获取文件流
instream = localFile.getInputStream();
// 跳到每个分块的开头
instream.skip(this.startPos);

// 创建UploadPartRequest,上传分块
UploadPartRequest uploadPartRequest = new UploadPartRequest();
uploadPartRequest.setBucketName(bucketName);
uploadPartRequest.setKey(key);
uploadPartRequest.setUploadId(this.uploadId);
uploadPartRequest.setInputStream(instream);
uploadPartRequest.setPartSize(this.partSize);
uploadPartRequest.setPartNumber(this.partNumber);

UploadPartResult uploadPartResult = FileUploader.client.uploadPart(uploadPartRequest);
logger.info("Part#" + this.partNumber + " done\n");
synchronized (partETags) {
// 将返回的PartETag保存到List中。
partETags.add(uploadPartResult.getPartETag());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (instream != null) {
try {
// 关闭文件流
instream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

/**
* 初始化分块上传事件并生成uploadID,用来作为区分分块上传事件的唯一标识
*
* @return
*/
protected static String claimUploadId(String bucketName, String key) {
InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, key);
InitiateMultipartUploadResult result = FileUploader.client.initiateMultipartUpload(request);
logger.info(result.getUploadId());
return result.getUploadId();
}

/**
* 将文件分块进行升序排序并执行文件上传。
*
* @param uploadId
*/
protected static void completeMultipartUpload(String uploadId) {
// 将文件分块按照升序排序
Collections.sort(partETags, new Comparator<PartETag>() {
@Override
public int compare(PartETag p1, PartETag p2) {
return p1.getPartNumber() - p2.getPartNumber();
}
});

CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(bucketName,
key, uploadId, partETags);
// 完成分块上传
FileUploader.client.completeMultipartUpload(completeMultipartUploadRequest);
}

/**
* 列出文件所有分块的清单
*
* @param uploadId
*/
protected static void listAllParts(String uploadId) {
ListPartsRequest listPartsRequest = new ListPartsRequest(bucketName, key, uploadId);
// 获取上传的所有分块信息
PartListing partListing = FileUploader.client.listParts(listPartsRequest);

// 获取分块的大小
int partCount = partListing.getParts().size();
// 遍历所有分块
for (int i = 0; i < partCount; i++) {
PartSummary partSummary = partListing.getParts().get(i);
logger.info("分块编号 " + partSummary.getPartNumber() + ", ETag=" + partSummary.getETag());
}
}
}


文件上传代码:

package com.changba.erp.utils;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import com.aliyun.oss.OSSClient;

public class FileUploader {

private static String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
private static String accessKeyId = "FAsc5DqUOpCMZqv8";
private static String accessKeySecret = "ewbsDctAbvNQbBl4d66mcoYgNC9N9T";
private static String bucketName = "mysong";

protected static OSSClient client = null;

private static Logger logger = LoggerFactory.getLogger(FileUploader.class);

public static String fileUpload(MultipartFile file) {

// 创建一个可重用固定线程数的线程池。若同一时间线程数大于10,则多余线程会放入队列中依次执行
ExecutorService executorService = Executors.newFixedThreadPool(10);

String key = file.getOriginalFilename(); // 获取上传文件的名称,作为在OSS上的文件名
// 创建OSSClient实例
client = new OSSClient(endpoint, accessKeyId, accessKeySecret);
try {
String uploadId = AliyunOSSUpload.claimUploadId(bucketName, key);
// 设置每块为 5M(除最后一个分块以外,其他的分块大小都要大于5MB)
final long partSize = 5 * 1024 * 1024L;
// 计算分块数目
long fileLength = file.getSize();
int partCount = (int) (fileLength / partSize);
if (fileLength % partSize != 0) {
partCount++;
}

// 分块 号码的范围是1~10000。如果超出这个范围,OSS将返回InvalidArgument的错误码。
if (partCount > 10000) {
throw new RuntimeException("文件过大(分块大小不能超过10000)");
} else {
logger.info("一共分了 " + partCount + " 块");
}

/**
* 将分好的文件块加入到list集合中
*/
for (int i = 0; i < partCount; i++) {
long startPos = i * partSize;
long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize;

// 线程执行。将分好的文件块加入到list集合中
executorService.execute(new AliyunOSSUpload(file, startPos, curPartSize, i + 1, uploadId, key, bucketName));
}

/**
* 等待所有分片完毕
*/
// 关闭线程池(线程池不马上关闭),执行以前提交的任务,但不接受新任务。
executorService.shutdown();
// 如果关闭后所有任务都已完成,则返回 true。
while (!executorService.isTerminated()) {
try {
// 用于等待子线程结束,再继续执行下面的代码
executorService.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

/**
* partETags(上传块的ETag与块编号(PartNumber)的组合) 如果校验与之前计算的分块大小不同,则抛出异常
*/
System.out.println(AliyunOSSUpload.partETags.size() +" ----- "+partCount);
if (AliyunOSSUpload.partETags.size() != partCount) {
throw new IllegalStateException("OSS分块大小与文件所计算的分块大小不一致");
} else {
logger.info("将要上传的文件名 " + key + "\n");
}

/*
* 列出文件所有的分块清单并打印到日志中,该方法仅仅作为输出使用
*/
AliyunOSSUpload.listAllParts(uploadId);

/*
* 完成分块上传
*/
AliyunOSSUpload.completeMultipartUpload(uploadId);

// 返回上传文件的URL地址
return endpoint + "/" + bucketName + "/" + client.getObject(bucketName, key).getKey();

} catch (Exception e) {
logger.error("上传失败!", e);
return "上传失败!";
} finally {
AliyunOSSUpload.partETags.clear();
if (client != null) {
client.shutdown();
}
}
}
}



举报

相关推荐

0 条评论