Ajax+Java实现大文件切割上传

时间:2023-03-09 03:33:03
Ajax+Java实现大文件切割上传

技术体系:html5(formdata) + java + servlet3.0+maven + tomcat7

 <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>大文件切割上传</title>
<style>
#wrap{width:600px; height:400px; border:1px solid #ccc; margin:10px auto;} </style>
</head>
<body>
<p>文件上传:<input type="file" id="file" onchange="uploadFile(this);"></p>
</body>
</html>
<script>
function uploadFile(file){
var File = file.files[0];
var totalSize = File.size; //文件总大小
var splitSize = 10 * 1024 * 1024; //10M 切割文件大小
var len = Math.ceil(totalSize/splitSize);
var fileName = File.name;
var xhr = new XMLHttpRequest();
var isLast = false;
var step = Math.ceil(100/len);
for(var i = 0 ; i< len;i++){
blob = File.slice(i*splitSize,splitSize*(i+1));
isLast = (i == len-1) ? true:false;
var result = upload(blob,i);
console.log("上传结果:" + result);
} function upload(blob,index){
var formData = new FormData();
formData.append("index",index);
formData.append("fileName",fileName);
formData.append("isLast",isLast);
formData.append("splitSize",splitSize);
formData.append("file",blob);
xhr.open("POST", "ajax4.do",false);
xhr.send(formData);
return xhr.responseText;
} } </script>

后台代码:

 package com.sgepit.ajax;

 import java.io.IOException;

 import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part; @WebServlet("/ajax4.do")
@MultipartConfig
public class Ajax4 extends HttpServlet { final String uploadPath = "D:/uploadFile/"; @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String index = req.getParameter("index");
String fileName = req.getParameter("fileName");
String isLast = req.getParameter("isLast");
String splitSize = req.getParameter("splitSize");
splitSize = null == splitSize ? "0" : splitSize; int size = Integer.parseInt(splitSize); Part part = req.getPart("file");
try {
if(null != part && part.getSize() != 0){
StringBuffer sbRealPath = new StringBuffer();
sbRealPath.append(uploadPath).append(index).append(".").append("part");
//写入文件
part.write(sbRealPath.toString());
if("true".equals(isLast)){ //如果是最后一次加载,准备合并文件
FileUtil fileUtil = new FileUtil();
fileUtil.mergePartFiles(uploadPath, ".part", size, uploadPath+fileName);
Thread.sleep(3000); //睡眠3秒以后再删除
fileUtil.deleteSplitFiles(uploadPath,".part");
}
resp.getWriter().write("success");
}
} catch (Exception e) {
e.printStackTrace();
} } }

工具方法:

 package com.sgepit.ajax;

 import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; /**
* 文件处理辅助类
*
*/
public class FileUtil { /**
* 获取指定目录下特定文件后缀名的文件列表(不包括子文件夹)
* @param dirPath 目录路径
* @param suffix 文件后缀
* @return
*/
public static ArrayList<File> getDirFiles(String dirPath,final String suffix) {
File path = new File(dirPath);
File[] fileArr = path.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
String lowerName = name.toLowerCase();
String lowerSuffix = suffix.toLowerCase();
if (lowerName.endsWith(lowerSuffix)) {
return true;
}
return false;
} });
ArrayList<File> files = new ArrayList<File>(); for (File f : fileArr) {
if (f.isFile()) {
files.add(f);
}
}
return files;
} /**
* 合并文件
*
* @param dirPath 上传文件所在的目录名称
* @param partFileSuffix 拆分文件后缀名
* @param partFileSize拆分文件的字节数大小
* @param mergeFileName 合并后的文件名
* @throws IOException
*/
public void mergePartFiles(String dirPath, String partFileSuffix,
int partFileSize, String mergeFileName) throws IOException {
ArrayList<File> partFiles = FileUtil.getDirFiles(dirPath, partFileSuffix);
Collections.sort(partFiles, new FileComparator()); RandomAccessFile randomAccessFile = new RandomAccessFile(mergeFileName,"rw");
randomAccessFile.setLength(partFileSize * (partFiles.size() - 1)
+ partFiles.get(partFiles.size() - 1).length());
randomAccessFile.close(); ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
partFiles.size(), partFiles.size() * 3, 1, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(partFiles.size() * 2)); for (int i = 0; i < partFiles.size(); i++) {
threadPool.execute(new MergeRunnable(i * partFileSize,mergeFileName, partFiles.get(i)));
}
} /**删除临时文件
* @param dirPath
* @param partFileSuffix
*/
public void deleteSplitFiles(String dirPath,String partFileSuffix){
ArrayList<File> partFiles = FileUtil.getDirFiles(dirPath, partFileSuffix);
for (int i = 0; i < partFiles.size(); i++) {
partFiles.get(i).delete();
} } /**
* 根据文件名,比较文件 ,根据文件名排序
*/
private class FileComparator implements Comparator<File> {
public int compare(File o1, File o2) {
return o1.getName().compareToIgnoreCase(o2.getName());
}
} /**
* 合并处理Runnable
*
*/
private class MergeRunnable implements Runnable {
long startPos;
String mergeFileName;
File partFile; public MergeRunnable(long startPos, String mergeFileName, File partFile) {
this.startPos = startPos;
this.mergeFileName = mergeFileName;
this.partFile = partFile;
} public void run() {
RandomAccessFile rFile;
try {
rFile = new RandomAccessFile(mergeFileName, "rw");
rFile.seek(startPos);
FileInputStream fs = new FileInputStream(partFile);
byte[] b = new byte[fs.available()];
fs.read(b);
fs.close();
rFile.write(b);
rFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} }

备注:一定要注意,在maven环境下,启动tomcat的时候,一定要用tomcat7:run, 而不是tomcat:run,否则无法正常使用。(踩坑了)