Ajax+Java实现大文件切割上传
技术体系:html5(formdata) + java + servlet3.0+maven + tomcat7
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title>大文件切割上传</title> 6 <style> 7 #wrap{width:600px; height:400px; border:1px solid #ccc; margin:10px auto;} 8 9 </style> 10 </head> 11 <body> 12 <p>文件上传:<input type="file" id="file" onchange="uploadFile(this);"></p> 13 </body> 14 </html> 15 <script> 16 function uploadFile(file){ 17 var File = file.files[0]; 18 var totalSize = File.size; //文件总大小 19 var splitSize = 10 * 1024 * 1024; //10M 切割文件大小 20 var len = Math.ceil(totalSize/splitSize); 21 var fileName = File.name; 22 var xhr = new XMLHttpRequest(); 23 var isLast = false; 24 var step = Math.ceil(100/len); 25 for(var i = 0 ; i< len;i++){ 26 blob = File.slice(i*splitSize,splitSize*(i+1)); 27 isLast = (i == len-1) ? true:false; 28 var result = upload(blob,i); 29 console.log("上传结果:" + result); 30 } 31 32 function upload(blob,index){ 33 var formData = new FormData(); 34 formData.append("index",index); 35 formData.append("fileName",fileName); 36 formData.append("isLast",isLast); 37 formData.append("splitSize",splitSize); 38 formData.append("file",blob); 39 xhr.open("POST", "ajax4.do",false); 40 xhr.send(formData); 41 return xhr.responseText; 42 } 43 44 } 45 46 </script>
后台代码:
1 package com.sgepit.ajax; 2 3 import java.io.IOException; 4 5 import javax.servlet.ServletException; 6 import javax.servlet.annotation.MultipartConfig; 7 import javax.servlet.annotation.WebServlet; 8 import javax.servlet.http.HttpServlet; 9 import javax.servlet.http.HttpServletRequest; 10 import javax.servlet.http.HttpServletResponse; 11 import javax.servlet.http.Part; 12 13 @WebServlet("/ajax4.do") 14 @MultipartConfig 15 public class Ajax4 extends HttpServlet { 16 17 final String uploadPath = "D:/uploadFile/"; 18 19 @Override 20 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 21 String index = req.getParameter("index"); 22 String fileName = req.getParameter("fileName"); 23 String isLast = req.getParameter("isLast"); 24 String splitSize = req.getParameter("splitSize"); 25 splitSize = null == splitSize ? "0" : splitSize; 26 27 int size = Integer.parseInt(splitSize); 28 29 Part part = req.getPart("file"); 30 try { 31 if(null != part && part.getSize() != 0){ 32 StringBuffer sbRealPath = new StringBuffer(); 33 sbRealPath.append(uploadPath).append(index).append(".").append("part"); 34 //写入文件 35 part.write(sbRealPath.toString()); 36 if("true".equals(isLast)){ //如果是最后一次加载,准备合并文件 37 FileUtil fileUtil = new FileUtil(); 38 fileUtil.mergePartFiles(uploadPath, ".part", size, uploadPath+fileName); 39 Thread.sleep(3000); //睡眠3秒以后再删除 40 fileUtil.deleteSplitFiles(uploadPath,".part"); 41 } 42 resp.getWriter().write("success"); 43 } 44 } catch (Exception e) { 45 e.printStackTrace(); 46 } 47 48 } 49 50 }
工具方法:
1 package com.sgepit.ajax; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.FilenameFilter; 6 import java.io.IOException; 7 import java.io.RandomAccessFile; 8 import java.util.ArrayList; 9 import java.util.Collections; 10 import java.util.Comparator; 11 import java.util.concurrent.ArrayBlockingQueue; 12 import java.util.concurrent.ThreadPoolExecutor; 13 import java.util.concurrent.TimeUnit; 14 15 /** 16 * 文件处理辅助类 17 * 18 */ 19 public class FileUtil { 20 21 /** 22 * 获取指定目录下特定文件后缀名的文件列表(不包括子文件夹) 23 * @param dirPath 目录路径 24 * @param suffix 文件后缀 25 * @return 26 */ 27 public static ArrayList<File> getDirFiles(String dirPath,final String suffix) { 28 File path = new File(dirPath); 29 File[] fileArr = path.listFiles(new FilenameFilter() { 30 public boolean accept(File dir, String name) { 31 String lowerName = name.toLowerCase(); 32 String lowerSuffix = suffix.toLowerCase(); 33 if (lowerName.endsWith(lowerSuffix)) { 34 return true; 35 } 36 return false; 37 } 38 39 }); 40 ArrayList<File> files = new ArrayList<File>(); 41 42 for (File f : fileArr) { 43 if (f.isFile()) { 44 files.add(f); 45 } 46 } 47 return files; 48 } 49 50 51 /** 52 * 合并文件 53 * 54 * @param dirPath 上传文件所在的目录名称 55 * @param partFileSuffix 拆分文件后缀名 56 * @param partFileSize拆分文件的字节数大小 57 * @param mergeFileName 合并后的文件名 58 * @throws IOException 59 */ 60 public void mergePartFiles(String dirPath, String partFileSuffix, 61 int partFileSize, String mergeFileName) throws IOException { 62 ArrayList<File> partFiles = FileUtil.getDirFiles(dirPath, partFileSuffix); 63 Collections.sort(partFiles, new FileComparator()); 64 65 RandomAccessFile randomAccessFile = new RandomAccessFile(mergeFileName,"rw"); 66 randomAccessFile.setLength(partFileSize * (partFiles.size() - 1) 67 + partFiles.get(partFiles.size() - 1).length()); 68 randomAccessFile.close(); 69 70 ThreadPoolExecutor threadPool = new ThreadPoolExecutor( 71 partFiles.size(), partFiles.size() * 3, 1, TimeUnit.SECONDS, 72 new ArrayBlockingQueue<Runnable>(partFiles.size() * 2)); 73 74 for (int i = 0; i < partFiles.size(); i++) { 75 threadPool.execute(new MergeRunnable(i * partFileSize,mergeFileName, partFiles.get(i))); 76 } 77 } 78 79 /**删除临时文件 80 * @param dirPath 81 * @param partFileSuffix 82 */ 83 public void deleteSplitFiles(String dirPath,String partFileSuffix){ 84 ArrayList<File> partFiles = FileUtil.getDirFiles(dirPath, partFileSuffix); 85 for (int i = 0; i < partFiles.size(); i++) { 86 partFiles.get(i).delete(); 87 } 88 89 } 90 91 /** 92 * 根据文件名,比较文件 ,根据文件名排序 93 */ 94 private class FileComparator implements Comparator<File> { 95 public int compare(File o1, File o2) { 96 return o1.getName().compareToIgnoreCase(o2.getName()); 97 } 98 } 99 100 /** 101 * 合并处理Runnable 102 * 103 */ 104 private class MergeRunnable implements Runnable { 105 long startPos; 106 String mergeFileName; 107 File partFile; 108 109 public MergeRunnable(long startPos, String mergeFileName, File partFile) { 110 this.startPos = startPos; 111 this.mergeFileName = mergeFileName; 112 this.partFile = partFile; 113 } 114 115 public void run() { 116 RandomAccessFile rFile; 117 try { 118 rFile = new RandomAccessFile(mergeFileName, "rw"); 119 rFile.seek(startPos); 120 FileInputStream fs = new FileInputStream(partFile); 121 byte[] b = new byte[fs.available()]; 122 fs.read(b); 123 fs.close(); 124 rFile.write(b); 125 rFile.close(); 126 } catch (IOException e) { 127 e.printStackTrace(); 128 } 129 } 130 } 131 132 }
备注:一定要注意,在maven环境下,启动tomcat的时候,一定要用tomcat7:run, 而不是tomcat:run,否则无法正常使用。(踩坑了)