【OSS】OSS的Multipart上传

OSS中大文件上传建议使用

Mu
package com.ls;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import com.aliyun.oss.ClientConfiguration;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSErrorCode;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.ServiceException;
import com.aliyun.oss.model.AbortMultipartUploadRequest;
import com.aliyun.oss.model.CompleteMultipartUploadRequest;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.InitiateMultipartUploadRequest;
import com.aliyun.oss.model.InitiateMultipartUploadResult;
import com.aliyun.oss.model.ListMultipartUploadsRequest;
import com.aliyun.oss.model.MultipartUpload;
import com.aliyun.oss.model.MultipartUploadListing;
import com.aliyun.oss.model.OSSObjectSummary;
import com.aliyun.oss.model.ObjectListing;
import com.aliyun.oss.model.PartETag;
import com.aliyun.oss.model.UploadPartRequest;
import com.aliyun.oss.model.UploadPartResult;

/**
 * 该示例代码展示了如何使用OSS的Multipart上传方式进行多线程分段上传较大文件。
 * 
 * 该示例代码执行的过程为: 
 * 1. 检查指定的Bucket是否存在,如果不存在则创建它;
 * 2. 根据文件的大小计算应该将文件分成多少个Part进行上传; 
 * 3.初始化Multipart上传请求; 
 * 4. 使用ExecutorService并发在上传每个Part; 
 * 5.如果所有Part均上传成功,则完成这个上传请求; 
 * 6.最后清理掉测试资源:删除上传的Object或未完成的Multipart上传请求,并删除这个Bucket。
 * 
 * 尝试运行这段示例代码时需要注意: 
 * 1.为了展示在删除Bucket时除了需要删除其中的Objects,也需要取消掉未完成的Multipartuploads, 示例代码最后为删除掉指定的Bucket,因为不要使用您的已经有资源的Bucket进行测试! 
 * 2.请使用您的API授权密钥填充ACCESS_ID和ACCESS_KEY常量; 
 * 3.需要准确上传用的测试文件,该文件大小要大于一个Part的最小字节数5MB,但不能大于 一个Object允许的最大字节数5GB。
 * 并修改常量UPLOAD_FILE_PATH为测试文件的路径;修改常量DOWNLOAD_FILE_PATH为下载文件的路径。 
 * 4.该程序仅为示例代码,仅供参考,并不能保证足够健壮。
 **/
public class OSSMultipartSample {

	private static final String ACCESS_ID = "******************";
	private static final String ACCESS_KEY = "*************************";
	private static final String OSS_ENDPOINT = "http://oss.aliyuncs.com/";

	private static final String UPLOAD_FILE_PATH = "G:/test/Maven实战.pdf";
	private static final String DOWNLOAD_FILE_PATH = "G:/test/download/Maven实战.pdf";

	private static final long PART_SIZE = 5 * 1024 * 1024L; // 每个Part的大小,最小为5MB
	private static final int CONCURRENCIES = 2; // 上传Part的并发线程数。

	public static void main(String[] args) throws Exception {
		// 可以使用ClientConfiguration对象设置代理服务器、最大重试次数等参数。
		ClientConfiguration config = new ClientConfiguration();
		OSSClient client = new OSSClient(OSS_ENDPOINT, ACCESS_ID, ACCESS_KEY,
				config);

		String bucketName = ACCESS_ID.toLowerCase() + "-multipart-test";

		System.out.println("ACCESS_ID.toLowerCase():" + ACCESS_ID.toLowerCase());

		String key = "Maven实战.pdf";

		File uploadFile = new File(UPLOAD_FILE_PATH);
		if (!uploadFile.exists())
			System.err.println("无法找到文件:" + UPLOAD_FILE_PATH);

		// 准备Bucket
		ensureBucket(client, bucketName);

		try {

			// 使用multipart的方式上传文件
			System.out.println("正在上传...");
			long startTime = System.currentTimeMillis();
			uploadBigFile(client, bucketName, key, uploadFile);
			long endTime = System.currentTimeMillis();
			System.out.println("上传花费时间约:" + (endTime - startTime) + " ms");

			// 下载上传完成的Object
			System.out.println("正在下载...");
			long startTime_d = System.currentTimeMillis();
			downloadFile(client, bucketName, key, DOWNLOAD_FILE_PATH);
			long endTime_d = System.currentTimeMillis();
			System.out.println("下载花费时间约:" + (endTime_d - startTime_d) + " ms");
		} finally {
			// 清理测试资源
			deleteBucket(client, bucketName);
		}
	}

	// 创建Bucket
	private static void ensureBucket(OSSClient client, String bucketName)
			throws OSSException, ClientException {

		try {
			// 创建bucket
			client.createBucket(bucketName);
		} catch (ServiceException e) {
			if (!OSSErrorCode.BUCKET_ALREADY_EXISTS.equals(e.getErrorCode())) {
				// 如果Bucket已经存在,则忽略
				throw e;
			}
		}
	}

	// 删除掉Bucket
	private static void deleteBucket(OSSClient client, String bucketName)
			throws OSSException, ClientException {

		// 删除bucket之前必须保证bucket为空,所以先必须先删除object和multipart

		// 如果存在,查看bucket是否为空
		ObjectListing ObjectListing = client.listObjects(bucketName);
		List listDeletes = ObjectListing.getObjectSummaries();
		for (int i = 0; i < listDeletes.size(); i++) {
			String objectName = listDeletes.get(i).getKey();
			// 如果不为空,先删除bucket下的文件
			client.deleteObject(bucketName, objectName);
		}

		// 删除所有未完成的multipart uploads.
		ListMultipartUploadsRequest listMultipartUploadsRequest = new ListMultipartUploadsRequest(
				bucketName);
		MultipartUploadListing uploadListing = client
				.listMultipartUploads(listMultipartUploadsRequest);

		for (MultipartUpload upload : uploadListing.getMultipartUploads()) {
			String key = upload.getKey();
			AbortMultipartUploadRequest abortMultipartUploadRequest = new AbortMultipartUploadRequest(
					bucketName, key, upload.getUploadId());

			client.abortMultipartUpload(abortMultipartUploadRequest);
		}

		// 删除bucket
		client.deleteBucket(bucketName);
	}

	// 通过Multipart的方式上传一个大文件
	// 要上传文件的大小必须大于一个Part允许的最小大小,即5MB。
	private static void uploadBigFile(OSSClient client, String bucketName,
			String key, File uploadFile) throws OSSException, ClientException,
			InterruptedException {

		int partCount = calPartCount(uploadFile);
		if (partCount <= 1) {
			throw new IllegalArgumentException("要上传文件的大小必须大于一个Part的字节数:"
					+ PART_SIZE);
		}

		String uploadId = initMultipartUpload(client, bucketName, key);

		ExecutorService pool = Executors.newFixedThreadPool(CONCURRENCIES);

		List eTags = Collections
				.synchronizedList(new ArrayList());

		for (int i = 0; i < partCount; i++) {
			System.out.println("正在上传第" + i + "部分");
			long start = PART_SIZE * i;
			long curPartSize = PART_SIZE < uploadFile.length() - start ? PART_SIZE
					: uploadFile.length() - start;

			pool.execute(new UploadPartThread(client, bucketName, key,
					uploadFile, uploadId, i + 1, PART_SIZE * i, curPartSize,
					eTags));
		}

		pool.shutdown();
		while (!pool.isTerminated()) {
			pool.awaitTermination(5, TimeUnit.SECONDS);
		}

		if (eTags.size() != partCount) {
			throw new IllegalStateException("Multipart上传失败,有Part未上传成功。");
		}

		completeMultipartUpload(client, bucketName, key, uploadId, eTags);
	}

	// 根据文件的大小和每个Part的大小计算需要划分的Part个数。
	private static int calPartCount(File f) {
		int partCount = (int) (f.length() / PART_SIZE);
		if (f.length() % PART_SIZE != 0) {
			partCount++;
		}
		return partCount;
	}

	// 初始化一个Multi-part upload请求。
	private static String initMultipartUpload(OSSClient client,
			String bucketName, String key) throws OSSException, ClientException {
		InitiateMultipartUploadRequest initUploadRequest = new InitiateMultipartUploadRequest(
				bucketName, key);
		InitiateMultipartUploadResult initResult = client
				.initiateMultipartUpload(initUploadRequest);
		String uploadId = initResult.getUploadId();
		return uploadId;
	}

	// 完成一个multi-part请求。
	private static void completeMultipartUpload(OSSClient client,
			String bucketName, String key, String uploadId, List eTags)
			throws OSSException, ClientException {
		// 为part按partnumber排序
		Collections.sort(eTags, new Comparator() {

			public int compare(PartETag arg0, PartETag arg1) {
				PartETag part1 = arg0;
				PartETag part2 = arg1;

				return part1.getPartNumber() - part2.getPartNumber();
			}
		});

		CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(
				bucketName, key, uploadId, eTags);

		client.completeMultipartUpload(completeMultipartUploadRequest);
	}

	private static class UploadPartThread implements Runnable {
		private File uploadFile;
		private String bucket;
		private String object;
		private long start;
		private long size;
		private List eTags;
		private int partId;
		private OSSClient client;
		private String uploadId;

		UploadPartThread(OSSClient client, String bucket, String object,
				File uploadFile, String uploadId, int partId, long start,
				long partSize, List eTags) {
			this.uploadFile = uploadFile;
			this.bucket = bucket;
			this.object = object;
			this.start = start;
			this.size = partSize;
			this.eTags = eTags;
			this.partId = partId;
			this.client = client;
			this.uploadId = uploadId;
		}

		@Override
		public void run() {

			InputStream in = null;
			try {
				in = new FileInputStream(uploadFile);
				in.skip(start);

				UploadPartRequest uploadPartRequest = new UploadPartRequest();
				uploadPartRequest.setBucketName(bucket);
				uploadPartRequest.setKey(object);
				uploadPartRequest.setUploadId(uploadId);
				uploadPartRequest.setInputStream(in);
				uploadPartRequest.setPartSize(size);
				uploadPartRequest.setPartNumber(partId);

				UploadPartResult uploadPartResult = client
						.uploadPart(uploadPartRequest);

				eTags.add(uploadPartResult.getPartETag());

			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				if (in != null)
					try {
						in.close();
					} catch (Exception e) {
					}
			}
		}
	}

	// 下载Object到本地文件。
	private static void downloadFile(OSSClient client, String bucketName,
			String key, String downloadFilePath) throws OSSException,
			ClientException {
		client.getObject(new GetObjectRequest(bucketName, key), new File(
				downloadFilePath));
	}
}

ltipart上传方式。

你可能感兴趣的:(阿里云)