阿里云OSS-大文件-分片上传

首先抱歉我忘记了最初版本是摘自哪位大牛的了,实在不好意思,感谢他/她;

粗糙测试:postman同时(相差2秒内)send请求访问阿里云OSS的普通上传和分片上传212MB的eclipse-jee-indigo-SR2-64.zip;

得到21:7:13========21:9:7(分片)--->耗时2分钟

得到21:7:11================21:15:23(普通上传)--->耗时8分钟


至于拿配置文件里面的值的方法.恕我不能展示出来,那些是公司的代码, 其实也很简单,但是使用的是公司内部封装的,其实底层也就是jdk的api, 并且这种方式是比较老的,不是框架直接注解@就导入. 大家用自己习惯的方式注入值就好了.(建议不要把值直接写在类里)

整个类import比较简单 只有aliyunOss必须的一个sdk:《aliyun-sdk-oss-2.3.0.jar》


注意:

①由于是测试, 所以这个工具类我给它加了@Controller注解和对应的接口url,实际运用时, emmmm,你们自己看着办吧。当工具类调用也可以,直接当上传视频的接口也可以。 

②由于是测试, 我返回return的是时间差, 你们要用来上传到阿里云OSS储存桶的时候把 被注释掉的那行return解封,把下面的时间代码删除即可。


````
import java.util.Date;
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.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import com.aliyun.oss.OSSClient;
/**
 * @author Berton
 * @time: 2018年2月11日 下午14:23:12
 */
@Controller
public class FileUploader {

	private static String endpoint = "";//买的阿里云的位置
	private static String accessKeyId = "";//阿里云账号的KeyId
	private static String accessKeySecret = "";//阿里云账号的KeySecret
	private static String bucketName = "";//阿里云上自己桶的名字

	protected static OSSClient client = null;//创建阿里云服务器连接对象

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

	@RequestMapping(value = "heiheihei", method = { RequestMethod.POST })
	@ResponseBody
	public static String fileUpload(MultipartFile file) {
		Date date = new Date();
		String beginTime = date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds();
		OSSConfig config = null;
		// 创建一个可重用固定线程数的线程池。若同一时间线程数大于10,则多余线程会放入队列中依次执行
		ExecutorService executorService = Executors.newFixedThreadPool(10);
		// 完整的文件名
		String key = file.getOriginalFilename();
		// 创建OSSClient实例
		config = config == null ? new OSSConfig() : config;
		//从自己的配置文件里面取值
		endpoint = config.getEndpoint();
		accessKeyId = config.getAccessKeyId();
		accessKeySecret = config.getAccessKeySecret();
		bucketName = config.getBucketName();
		client = new OSSClient(endpoint, accessKeyId, accessKeySecret);//根据阿里云用户配置创建连接对象实例
		try {
			String uploadId = AliyunOSSUpload.claimUploadId(bucketName, key);// key是文件名 By berton
			// 设置每块为 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++) {
				// 起始point
				long startPos = i * partSize;
				// 判断当前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.replaceFirst("http://","http://"+bucketName+".")+"/"+key ;
			Date date2 = new Date();
			String endTime = date2.getHours() + ":" + date2.getMinutes() + ":" + date2.getSeconds();
			return beginTime + "========" + endTime;

		} catch (Exception e) {
			logger.error("上传失败!", e);
			return "上传失败!";
		} finally {
			AliyunOSSUpload.partETags.clear();
			if (client != null) {
				client.shutdown();
			}
		}
	}
}
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());  
        }  
    }  
}  

````
  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值