分片上传
1.查询是否已经上传
2.分片发送
3.提交
注意,md5加密,是通过加密文件的前1024个字节,md5加密如果是通过字节数组加密,会有安全问题,所有改成加密流。
这个有一个问题,如果是txt文件,前1024个字节都是一样的情况下,后面的内容不管怎么变,文件都会被加一样的密
每次分片上传2M
import org.apache.http.HttpEntity;
import org.apache.http.HttpRequest;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
public class FileUploadUtil{
private final int UPLOAD_PART_SIZE = 1024 * 1024 * 2;
private final int SIZE_1024 = 1024;
private byte[] bytes = new byte[SIZE_1024];
public String uploadCloud(InputStream is, long fileSize, String fileName) throws Exception {
String fileMd5 = md5Stream(is, fileSize);
Boolean status = query(fileMd5, fileSize);
if (!status) {
saveData(is, fileMd5, fileName, fileSize);
}
return finish(fileMd5, fileName, fileSize);
}
private String md5Stream(InputStream is, long fileSize) throws IOException {
if (fileSize < SIZE_1024) {
bytes = new byte[(int) fileSize];
}
int num = is.read(bytes);
InputStream md5Is = new ByteArrayInputStream(bytes, 0, num);
return DigestUtils.md5Hex(md5Is);
}
private Boolean query(String fileMd5){
}
private void saveData(InputStream stream,String fileMd5, String fileName, long fileSize){
if (fileSize <= SIZE_1024) {
InputStream streamPart = new ByteArrayInputStream(bytes);
savePartData(fileMd5, 0L, streamPart, fileName, fileSize);
return;
}
long loop = fileSize / UPLOAD_PART_SIZE;
long last = fileSize % UPLOAD_PART_SIZE;
if (last > 0) {
loop += 1;
}
long chunk = 0;
// 分片号,表示文件分片的索引,从0开始
do {
byte[] buf = getBufBytes(loop, last, chunk);
byte[] merge = new byte[0];
if (chunk == 0) {
merge = new byte[buf.length + SIZE_1024];
}
int num = stream.read(buf);
if (chunk == 0) {
System.arraycopy(bytes, 0, merge, 0, SIZE_1024);
System.arraycopy(buf, 0, merge, SIZE_1024, num);
} else {
merge = buf;
}
// 分片上传,每次上传不超过2M
InputStream streamPart = new ByteArrayInputStream(merge);
savePartData(headerParamsMap, fileMd5, chunk, streamPart, fileName, fileSize);
chunk++;
} while (chunk < loop);
}
private byte[] getBufBytes(long loop, long last, long chunk) {
byte[] buf;
if (last > 0 && chunk == loop - 1) {
if (chunk == 0) {
buf = new byte[(int) last - bytes.length];
} else {
buf = new byte[(int) last];
}
} else if (chunk == 0) {
buf = new byte[UPLOAD_PART_SIZE - bytes.length];
} else {
buf = new byte[UPLOAD_PART_SIZE];
}
return buf;
}
private void savePartData(String fileMd5, Long chunk,InputStream streamPart, String fileName, long fileSize)IOException {
String url = 'http://xxxxxx';
HttpPost httpPost = new HttpPost(url);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addBinaryBody(FILE, streamPart, ContentType.MULTIPART_FORM_DATA, String.valueOf(chunk));
builder.addTextBody(FILE_MD5, fileMd5);
builder.addTextBody(FILE_NAME, fileName);
builder.addTextBody(CHUNK, String.valueOf(chunk));
builder.addTextBody(MD5_DIRECT_TRANSFER_ENABLE, String.valueOf(true));
builder.addTextBody(FILE_SIZE, String.valueOf(fileSize));
HttpEntity entity = builder.build();
httpPost.setEntity(entity);
/* 如果分片上传失败重试5次 */
Boolean send;
CloseableHttpClient client = null;
CloseableHttpResponse response = null;
int count = 4;
try {
client = HttpClients.createDefault();
do {
response = client.execute(httpPost);
String bo = responseParseStr(response, "sendPartData");
send = new Boolean(bo);
logger.info("sendPartData" + send);
} while (!send && count-- > 0);
} catch (Exception e) {
logger.error("sendPartData:", e);
throw new BusiException();
} finally {
try {
if (response != null) {
response.close();
}
if (client != null) {
client.close();
}
} catch (IOException e) {
logger.error("close exception:", e);
}
}
}
private String finish(String fileMd5, String fileName, long size) throws Exception {
String url = "xxxxxxx";
HttpPost httpPost = new HttpPost(url);
String id;
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addTextBody(FILE_MD5, fileMd5);
builder.addTextBody(FILE_NAME, fileName);
builder.addTextBody(FILE_SIZE, String.valueOf(size));
builder.addTextBody(MD5_DIRECT_TRANSFER_ENABLE, String.valueOf(true));
HttpEntity entity = builder.build();
httpPost.setEntity(entity);
try (CloseableHttpResponse response = HttpClients.createDefault().execute(httpPost)) {
JSONObject bo = responseParseJson(response);
id = bo.getString("key");
} catch (Exception e) {
logger.error("finishPartObject:", e);
throw new BusiException();
}
return id;
}
//下载 是通过一个上传的id来下载
@Override
public String download(String id, String fileName) throws BusiException, IOException {
if (StringUtils.isEmpty(id)) {
throw new BusiException();
}
String url = "xxxxxxxxxx";
HttpPost httpPost = new HttpPost(url);
// 请求参数 ENCRYP_VALUE: 1->只读 7->可编辑
List<Map<String, Object>> list = new ArrayList<>();
Map<String, Object> encryptProfile = new HashedMap(8);
encryptProfile.put(KEY, id);
encryptProfile.put(USE_ID, "zhangsan001");
encryptProfile.put(ENCRYP_ENABLE, false);
encryptProfile.put(ENCRYP_VALUE, 7);
encryptProfile.put(FIXED_READ, 1);
list.add(encryptProfile);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addTextBody(KEY, id);
builder.addTextBody(DOWNLOAD_NAME, fileName);
builder.addTextBody(LIMIT_COUNT, "-1");
builder.addTextBody(ENCRYPT_PROFILE, JSON.toJSONString(list));
HttpEntity entity = builder.build();
httpPost.setEntity(entity);
try (CloseableHttpResponse response = HttpClients.createDefault().execute(httpPost)) {
return 解析返回一个可以直接在浏览下载的url;
} catch (Exception e) {
logger.error("downloadToken:", e);
throw new BusiException();
}
}
}