大文件分片上传 多线程上传文件(发送端)

发送端 采用多线程发送

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;
	}

}

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值