发送端 采用多线程发送
package com.controller;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.form.UploadFileForm;
import com.util.UploadGetFileList;
import com.util.UploadGlobalConstant;
import com.util.UploadMidThread;
import com.util.UploadThreadRun;
@Controller
public class FileUploadController {
@Value("#{propertiesReader[duandian]}")
private boolean duandian;
@Value("#{propertiesReader[server_title]}")
private String server_title;
@Value("#{propertiesReader[uploadfile]}")
private String uploadfile;
@Value("#{propertiesReader[getPart]}")
private String getPart;
@Value("#{propertiesReader[deletePart]}")
private String deletePart;
private static final Logger logger = Logger.getLogger(FileUploadController.class);
@RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
@ResponseBody
public int uploadFile(@RequestBody UploadFileForm file_start)
throws Exception {
String file_start_upload = file_start.getFile_start_upload();
String dir = file_start.getDir();
String file_end_upload = file_start.getFile_end_upload();
logger.error("文件上传开始时间:" + new Date());
long begin = System.currentTimeMillis();
System.out.println("文件上传开始时间:" + new Date());
String uploadUrl = "";
String ip = file_start.getIp();
int port = file_start.getPort();
int body = 0;
if (ip != null && port != 0) {
uploadUrl = server_title + ip + ":" + port + uploadfile;
}
//启多线程上传
ExecutorService executorService = Executors.newFixedThreadPool(5);
File file = new File(file_start_upload);
List<String> lists = new ArrayList<>();
if (file.isDirectory()) {
UploadGetFileList fileList = new UploadGetFileList();
lists = fileList.GetSql(file_start_upload);
} else {
lists.add(file_start_upload);
}
if (lists.size() != 0) {
for (int i = 1; i <= lists.size(); i++) {
System.out.println(i);
String url = lists.get(i - 1);
System.out.println(url);
File targetFile = new File(url);
long targetFileSize = targetFile.length();
int mBlockNumber = number(targetFileSize);
String targetFilePath = urlSubString(lists.get(i - 1),
file_end_upload, dir);
String randomUUID = UUID.randomUUID().toString();
if(mBlockNumber==1){
executorService.execute(new UploadThreadRun(uploadUrl,
targetFile, mBlockNumber, 1,targetFilePath,
lists.get(i - 1), i,lists.size(), randomUUID));
}
//如果大文件再起一个线程池
else{
executorService.execute(new UploadMidThread(uploadUrl,
targetFile, mBlockNumber, targetFilePath,
lists.get(i - 1), i, lists.size(), randomUUID));
}
}
executorService.shutdown();
while (true) {
if (executorService.isTerminated()) {
long end = System.currentTimeMillis();
logger.error("文件上传结束时间:" + new Date());
long date=(end-begin)/1000;
if(date<60){
logger.error("耗时"+((end-begin)/1000)+"s");
}else{
long MM=date/60;
long ss=date%60;
logger.error("耗时"+(MM+"M:"+ss+"s"));
}
System.out.println("文件上传结束时间:" + new Date());
body = 1;
break;
}
}
}
return body;
}
public static int number(long targetFileSize) {
int mBlockNumber = 0;
if (targetFileSize < UploadGlobalConstant.CLOUD_API_LOGON_SIZE) { // 小于要分割的大小就是一块
mBlockNumber = 1;
} else {
mBlockNumber = (int) (targetFileSize / UploadGlobalConstant.CLOUD_API_LOGON_SIZE);
long someExtra = targetFileSize
% UploadGlobalConstant.CLOUD_API_LOGON_SIZE;
if (someExtra > 0) { // 剩下的不足一块要加1
mBlockNumber++;
}
}
return mBlockNumber;
}
public static String urlSubString(String targetFilePath,
String file_end_upload, String dir) {
String fileCopyFile = "";
int index = targetFilePath.indexOf(dir);
if (index != -1) {
int start = dir.length();
String str = targetFilePath.substring(start,
targetFilePath.length());
fileCopyFile = file_end_upload + str;
fileCopyFile = fileCopyFile.replace('/', '\\');
}
return fileCopyFile;
}
}
文件上传线程
package com.util;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import net.sf.json.JSONObject;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import com.controller.FileUploadController;
public class UploadThreadRun implements Runnable {
String serverURL;
File targetFile;
int blockNumber;
int blockIndex;
String targetFilePath;
String localFilePath;
int il;
int fileNumber;
String randomUUID;
private static final Logger logger = Logger.getLogger(UploadThreadRun.class);
public UploadThreadRun(){
}
public UploadThreadRun(String serverURL, File targetFile, int blockNumber,
int blockIndex, String targetFilePath,
String localFilePath, int il,int fileNumber,String randomUUID) {
this.serverURL = serverURL;
this.targetFile = targetFile;
this.blockNumber = blockNumber;
this.blockIndex = blockIndex;
this.targetFilePath = targetFilePath;
this.localFilePath = localFilePath;
this.il=il;
this.fileNumber=fileNumber;
this.randomUUID=randomUUID;
}
@Override
public void run() {
long begin = System.currentTimeMillis();
System.out.println("++++++++++++++++");
if(fileNumber>1){
if(blockNumber>1){
System.out.println("多文件分片上传 共需上传文件:"+fileNumber+"个,当前文件在列表中的位置:第"+il+"个,共"+blockNumber+"片,第"+blockIndex+"片,该文件路径"+localFilePath);
}else{
System.out.println("多文件上传 共需上传文件:"+fileNumber+"个,当前文件在列表中的位置:"+il+",该文件路径"+localFilePath);
}
}else{
if(blockNumber>1){
System.out.println("单文件上传 共"+blockNumber+"片,第"+blockIndex+"片,该文件路径"+localFilePath);
}else{
System.out.println("单文件上传 该文件路径"+localFilePath);
}
}
String content = "";
try {
DefaultHttpClient httpClient = new DefaultHttpClient();
httpClient.getParams().setParameter("http.socket.timeout",
60 * 60 * 1000);
HttpPost post = new HttpPost(serverURL);
MultipartEntity mpEntity = new MultipartEntity();
// 添加String类型就像表单提交一样,第一个参数是标识名,带二个是具体内容
mpEntity.addPart("blockNumber", new StringBody(blockNumber + "",Charset.forName("UTF-8")));
mpEntity.addPart("blockIndex", new StringBody(blockIndex + "",Charset.forName("UTF-8")));
mpEntity.addPart("targetFilePath", new StringBody(targetFilePath,Charset.forName("UTF-8")));
mpEntity.addPart("randomUUID", new StringBody(randomUUID,Charset.forName("UTF-8")));
if (targetFile != null && targetFile.exists()) {
UploadBlockStreamBody cBlockStreamBody = new UploadBlockStreamBody(
blockNumber, blockIndex, targetFile);
mpEntity.addPart("file", cBlockStreamBody);
}
post.setEntity(mpEntity);
HttpResponse response = httpClient.execute(post);
if(response.getStatusLine().getStatusCode()==200){
long end = System.currentTimeMillis();
long date=(end-begin)/1000;
if(date<60){
logger.error(localFilePath+"耗时"+((end-begin)/1000)+"s");
}else{
long MM=date/60;
long ss=date%60;
logger.error(localFilePath+"耗时"+(MM+"M:"+ss+"s"));
}
if(blockNumber>1){
if(fileComplete(randomUUID,localFilePath+".index",blockIndex,blockNumber)){
File file = new File(localFilePath);
boolean result=file.delete();
int tryCount = 0;
if (!result && tryCount++ < 10) {
System.gc();
result =file.delete();
logger.error("文件强制回收"+localFilePath);
System.out.println("文件强制回收"+localFilePath);
}
delEmptyPath(file.getParent());
}
}else{
File file = new File(localFilePath);
boolean result=file.delete();
int tryCount = 0;
if (!result&& tryCount++ < 10) {
System.gc();
result =file.delete();
logger.error("文件强制回收"+localFilePath);
System.out.println("文件强制回收"+localFilePath);
}
delEmptyPath(file.getParent());
}
}
else{
long end = System.currentTimeMillis();
long date=(end-begin)/1000;
if(date<60){
logger.error(localFilePath+"耗时"+((end-begin)/1000)+"s");
}else{
long MM=date/60;
long ss=date%60;
logger.error(localFilePath+"耗时"+(MM+"M:"+ss+"s"));
}
logger.error(response.getStatusLine().getStatusCode()+localFilePath);
}
httpClient.getConnectionManager().shutdown();
} catch (Exception e) {
e.printStackTrace();
}
}
public boolean isJson(String s) {
boolean flag = true;
try {
JSONObject.fromObject(s);
} catch (Exception e) {
flag = false;
}
return flag;
}
public static void delEmptyPath(String path){
File file = new File(path);
if(file.exists()&&file.isDirectory()){
File[] files = file.listFiles();
if(files!=null&&files.length>0)
return;
if(file.delete()){
delEmptyPath(file.getParent());
}
}
}
public static boolean fileComplete(String randomUUID, String fileIndexPath,
int index, int blockNumber) throws IOException {
File fileIndex = new File(fileIndexPath);
if (!fileIndex.exists()) {
RandomAccessFile fileIndexWrite = new RandomAccessFile(fileIndex, "rw");
fileIndexWrite.seek(0);
fileIndexWrite.write(randomUUID.getBytes());
fileIndexWrite.close();
}
RandomAccessFile fileIndexWrite = new RandomAccessFile(fileIndex, "rw");
fileIndexWrite.seek(0);
byte bys[] = new byte[randomUUID.length()];
fileIndexWrite.read(bys);
String udil = new String(bys);
if (udil.equals(randomUUID)) {
fileIndexWrite.seek(udil.length() + index * 4);
String number = String.valueOf(index) + ",";
fileIndexWrite.write(number.getBytes());
fileIndexWrite.seek(udil.length());
byte[] buff = new byte[4];
// 用于保存实际读取的字节数
int hasRead = 0;
// 循环读取
String fileContent = "";
while ((hasRead = fileIndexWrite.read(buff)) > 0) {
fileContent = fileContent + new String(buff, 0, hasRead);
}
fileIndexWrite.close();
String[] list = fileContent.split(",");
if (list.length == blockNumber) {
fileIndex.delete();
return true;
}
}
else {
fileIndexWrite.close();
fileIndex.delete();
RandomAccessFile fileIndexWriter = new RandomAccessFile(fileIndex, "rw");
fileIndexWriter.seek(0);
fileIndexWriter.write(randomUUID.getBytes());
fileIndexWriter.seek(udil.length() + index * 4);
String number = String.valueOf(index) + ",";
fileIndexWriter.write(number.getBytes());
fileIndexWriter.close();
}
return false;
}
}
大文件上传再起线程池 叫做中间线程用来调用上面的类
package com.util;
import java.io.File;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class UploadMidThread implements Runnable{
String serverURL;
File targetFile;
int blockNumber;
String targetFilePath;
String localFilePath;
int il;
int fileNumber;
String randomUUID;
public UploadMidThread(){
}
public UploadMidThread(String serverURL, File targetFile, int blockNumber,
String targetFilePath,String localFilePath,int il,int fileNumber,String randomUUID) {
this.serverURL = serverURL;
this.targetFile = targetFile;
this.blockNumber = blockNumber;
this.targetFilePath = targetFilePath;
this.localFilePath = localFilePath;
this.il=il;
this.fileNumber=fileNumber;
this.randomUUID=randomUUID;
}
@Override
public void run() {
ExecutorService executorService = Executors.newFixedThreadPool(5);
for (int index = 1; index <= blockNumber; index++) {
executorService.execute(new UploadThreadRun(serverURL,
targetFile, blockNumber, index, targetFilePath,
localFilePath, il,
fileNumber,randomUUID));
}
executorService.shutdown();
while (true) {
if (executorService.isTerminated()) {
System.out.println("文件上传结束时间:" + new Date());
break;
}
}
}
}
分片类控制 100M大小为一片
package com.util;
public class UploadGlobalConstant {
public static long CLOUD_API_LOGON_SIZE=104857600;
}
该类用来读文件,将文件读入输出流用来上传
package com.util;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import org.apache.http.entity.mime.content.AbstractContentBody;
public class UploadBlockStreamBody extends AbstractContentBody {
// 给MultipartEntity看的2个参数
private long blockSize = 0;// 本次分块上传的大小
private String fileName = null;// 上传文件名
// writeTo需要的3个参数
private int blockNumber = 0, blockIndex = 0;// blockNumber分块数;blockIndex当前第几块
private File targetFile = null;// 要上传的文件
private UploadBlockStreamBody(String mimeType) {
super(mimeType);
// TODO Auto-generated constructor stub
}
/**
* 自定义的ContentBody构造子
*
* @param blockNumber分块数
* @param blockIndex当前第几块
* @param targetFile要上传的文件
*/
public UploadBlockStreamBody(int blockNumber, int blockIndex,
File targetFile) {
this("application/octet-stream");
this.blockNumber = blockNumber;// blockNumber初始化
this.blockIndex = blockIndex;// blockIndex初始化
this.targetFile = targetFile;// targetFile初始化
this.fileName = targetFile.getName();// fileName初始化
// blockSize初始化
if (blockIndex < blockNumber) {// 不是最后一块,那就是固定大小了
this.blockSize = UploadGlobalConstant.CLOUD_API_LOGON_SIZE;
} else {// 最后一块
this.blockSize = targetFile.length()
- UploadGlobalConstant.CLOUD_API_LOGON_SIZE
* (blockNumber - 1);
}
}
@Override
public void writeTo(OutputStream out) throws IOException {
byte b[] = new byte[1024 * 1024 * 2];// 暂存容器
RandomAccessFile raf = new RandomAccessFile(targetFile, "r");// 负责读取数据
if (blockIndex == 1) {// 第一块
int n = 0;
long readLength = 0;// 记录已读字节数
while (readLength <= blockSize - 1024 * 1024 * 2) {// 大部分字节在这里读取
n = raf.read(b, 0, 1024 * 1024 * 2);
readLength += 1024 * 1024 * 2;
out.write(b, 0, n);
}
if (readLength <= blockSize) {// 余下的不足 1024 个字节在这里读取
n = raf.read(b, 0, (int) (blockSize - readLength));
out.write(b, 0, n);
}
} else if (blockIndex < blockNumber) {// 既不是第一块,也不是最后一块
raf.seek(UploadGlobalConstant.CLOUD_API_LOGON_SIZE
* (blockIndex - 1));// 跳过前[块数*固定大小
// ]个字节
int n = 0;
long readLength = 0;// 记录已读字节数
while (readLength <= blockSize - 1024 * 1024 * 2) {// 大部分字节在这里读取
n = raf.read(b, 0, 1024 * 1024 * 2);
readLength += 1024 * 1024 * 2;
out.write(b, 0, n);
}
if (readLength <= blockSize) {// 余下的不足 1024 个字节在这里读取
n = raf.read(b, 0, (int) (blockSize - readLength));
out.write(b, 0, n);
}
} else {// 最后一块
raf.seek(UploadGlobalConstant.CLOUD_API_LOGON_SIZE
* (blockIndex - 1));// 跳过前[块数*固定大小
// ]个字节
int n = 0;
while ((n = raf.read(b, 0, 1024 * 1024 * 2)) != -1) {
out.write(b, 0, n);
}
}
if (raf != null) {
raf.close();
}
out.flush();
//out.close();
//
// TODO 最后不要忘掉关闭out/raf
}
@Override
public String getCharset() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getTransferEncoding() {
// TODO Auto-generated method stub
return "binary";
}
@Override
public String getFilename() {
// TODO Auto-generated method stub
return fileName;
}
@Override
public long getContentLength() {
// TODO Auto-generated method stub
return blockSize;
}
}
参数类
package com.form;
public class UploadFileForm {
public String file_start_upload;
public String file_end_upload;
public String ip;
public int port;
public String dir;
public boolean superUpload;
public String getFile_start_upload() {
return file_start_upload;
}
public void setFile_start_upload(String file_start_upload) {
this.file_start_upload = file_start_upload;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getDir() {
return dir;
}
public void setDir(String dir) {
this.dir = dir;
}
public String getFile_end_upload() {
return file_end_upload;
}
public void setFile_end_upload(String file_end_upload) {
this.file_end_upload = file_end_upload;
}
public boolean isSuperUpload() {
return superUpload;
}
public void setSuperUpload(boolean superUpload) {
this.superUpload = superUpload;
}
}