一、步骤:
1.配置maven,引入阿里oss服务器提供的相关依赖
2.编写对应的工具类实现对文件分片上传的业务
3.使用junit进行测试
二、maven中引入的依赖如下
com.aliyun.oss
aliyun-sdk-oss
3.3.0
com.aliyun
aliyun-java-sdk-core
3.4.0
com.aliyun
aliyun-java-sdk-ram
3.0.0
com.aliyun
aliyun-java-sdk-sts
3.0.0
com.aliyun
aliyun-java-sdk-ecs
4.2.0
这里可能还需要引入Apache HttpClient ,其maven厂库为:
org.apache.httpcomponents
httpclient
4.5.7
三、编写相应的工具类。实现文件的分片上传功能
代码如下:
package com.SCT.weichatprogram.util;
import com.aliyun.oss.*;
import com.aliyun.oss.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.*;
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;
@Component
public class MutinPartUploadUtil {
private Logger logger=LoggerFactory.getLogger(MutinPartUploadUtil.class);
@Value("${aliyunoss.bucketName}")
private String bucketName;
@Value("${aliyunoss.endpoint}")
private String endpoint;
@Value("${aliyunoss.accessKeyId}")
private String accessKeyId;
@Value("${aliyunoss.accessKeySecret}")
private String getAccessKeySecret;
private OSS client=null;
//用来最后上传成功后,调取对象保存文件名
private String filelo="";
private final long partSize=1024*1024*1;
private ExecutorService executorService= Executors.newFixedThreadPool(5);
private List partETagList=Collections.synchronizedList(new ArrayList());//这里考虑集合的线程安全,通过Collections.synchronizedList转为线程安全
public Boolean sendMutinPart(String key,File message){
ClientBuilderConfiguration conf=new ClientBuilderConfiguration();
conf.setIdleConnectionTime(1000);
client=new OSSClientBuilder().build(endpoint,accessKeyId,getAccessKeySecret,conf);
try{
String uploadId=claimUploadId(key);
File file=message;
long fileLength=file.length();
int partCount=(int)(fileLength/partSize);
if(fileLength%partSize!=0){
partCount++;
}
if(partCount>50000){
throw new RuntimeException("toal parts count should not excend 10000");
}
else{
logger.info("total parts count "+partCount+"\n");
}
logger.info("Begin to upload multiparts to oss form file\n");
for(int i=0;i() {
@Override
public int compare(PartETag p1, PartETag p2) {
return p1.getPartNumber() - p2.getPartNumber();
}
});
logger.info("completing to upload multiparts\n");
//请求碎片的整合操作
CompleteMultipartUploadRequest completeMultipartUploadRequest=
new CompleteMultipartUploadRequest(bucketName,key,uploadId,partETagList);
client.completeMultipartUpload(completeMultipartUploadRequest);
}
private class PartUploader implements Runnable{
private File localFile;
private long startPos;
private long partSize;
private int partNumber;
private String uploadId;
private String key;
public PartUploader(File file,long startPos,long partSize,int partNumber,String uploadId,String key){
this.localFile=file;
this.startPos=startPos;
this.partSize=partSize;
this.partNumber=partNumber;
this.uploadId=uploadId;
this.key=key;
}
@Override
public void run() {
InputStream instream=null;
try{
instream=new FileInputStream(this.localFile);
instream.skip(this.startPos);
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=client.uploadPart(uploadPartRequest);
logger.info("Part#"+this.partNumber+"done\n");
synchronized (partETagList){
partETagList.add(uploadPartResult.getPartETag());
}
}catch (IOException e){
e.printStackTrace();
}finally{
if(instream!=null){
try{
instream.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
}
// public File createSampleFile() throws IOException {
// File file = File.createTempFile("oss-java-sdk-", ".txt");
// file.deleteOnExit();
//
// Writer writer = new OutputStreamWriter(new FileOutputStream(file));
// for (int i = 0; i < 100000; i++) {
// writer.write("abcdefghijklmnopqrstuvwxyz\n");
// writer.write("0123456789011234567890\n");
// }
// writer.close();
//
// return file;
// }
//
}
四、对自己编写的工具类进行junit测试
代码如下:
@Test
public void sendTextToOss(){
System.out.println("accessKey:");
File file= null;
try {
file = File.createTempFile("415","txt");
file.deleteOnExit();
Writer writer = new OutputStreamWriter(new FileOutputStream(file));
writer.write("5445455545sdufgusdgfuysadgfsaufgsdfuysgddfgusagufyugeuywuyfgygwequyfyuwegfuuewygfuuwyegfuyyuwegfygewuyfgewgewyygfewuygf" +
"wefgwyeqfguywegfyuweyuf" +
"wefweqgfuygewuyf" +
"ewfhjuweqhf8ewhfhewqihfiuhwqehfi");
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
uploadUtil.sendMutinPart("12345678hauhaush9.txt",file);
}
五、这里涉及到知识
1、多线程的知识:
一)、即thread和ExecutorService
ExecutorService运用线程池的形式进行线程的管理和线程的调用,其设计的思想就是多例模式,对线程数量进行限制,对线程统一管理。在这里不得不谈关于ExecutorService的关闭线程池的三个函数:shutdownNow()、shutdown()和awaitTermination(long timeout,TimeUnit unit)。
这三个函数的区别是:
shutdownNow()立即关闭线程池,不管是否还有线程未完成。其等级最高
shutdown()不会立即关闭线程池,直达想成完成后才将其关闭,其等级第二
awaitTermination(long timeout,TimeUnit unit)即等待阻塞线程完成,其时间通过timeout和时间单位unit进行设置。在上述代码中每5秒进行判断线程是否还有线程池是否终止,如果没有将继续进行循环处理。其通常和shutdown连用。其等级最低
2.关于集合线程安全的知识
什么是线程安全:对于一个全局变量而言,其所有的线程都能访问,其访问的先后顺序也不同。即线程a和线程b同时访问全局变量C,a去改全局变量C进行加一,而b去也去改全局变量C进行加一,在这个过程中可能会出现,线程b先读取数据C,线程a再读取数据C,并将其数值加一。这是线程b将数值也加一,可是其读取的数据时a改变之前的,最后结果就不对了。在这里也涉及到关于变量的可见性问题,对于每个线程都有自己的本地缓存池,其内存数值改变了,但线程中缓存值没有改变,这导致数据缓存不一致的问题。
回归正题:如何保证集合的线程安全:
1.运用Collections.synchronizedList(List)将对应的集合转变为加锁的集合。加锁就是同步锁,即线程其他线程的存在,多个线程按照相应的逻辑顺序进行共同合作完成业务,即同步问题,同步问题也往往包含互斥问题
2.运用线程安全的集合