Java实现文件分片上传
文章目录
- Java实现文件分片上传
- 为什么要使用分片上传
- 什么是分片上传?
- 前后端代码
Java实现文件分片上传
为什么要使用分片上传
在需要上传文件时,不可避免地会遇到上传文件内容过大,上传时间太长地问题,采用文件分片上传就可以解决这个问题。
什么是分片上传?
简单的说就是本来是需要一次搬一个很大的东西,比如是一大桶水,一次搬起来比较费事费力。我们可以把这一大桶水分装在几个或几十个或者更多的小瓶里,这样搬运起来就比较省力,也比较方便,等到目的地后,我们在将这些小瓶子里的水都倒回大桶里,这样就完成了一大桶水的搬运工作。这个将一大桶水分成许多小瓶子的过程就是分片的过程,最后将水倒回大桶的过程就是合并的过程。分片与合并也是文件分片上传的重要过程。
前后端代码
这个分片的过程是在前端实现的,上传完成后的合并工作是后端完成的。
前端代码:
DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>JS分片上传-极速上传title>
head>
<body>
<input type="file" name="slice" id="slice" >
<br/>
body>
<script src="http://libs.baidu.com/jquery/1.8.3/jquery.min.js">script>
<script type="text/javascript">$("#slice").change(function(event) {var file = $("#slice")[0].files[0];PostFile(file,0);});//执行分片上传function PostFile(file,i, uuid){var name = file.name, //文件名size = file.size, //总大小shardSize = 10 * 1024 * 1024, //以10MB为一个分片,每个分片的大小shardCount = Math.ceil(size / shardSize); //总片数if(i >= shardCount){return;}//判断uuid是否存在if (uuid === null || uuid === undefined) {uuid = guid();}//console.log(size,i+1,shardSize); //文件总大小,第一次,分片大小//var start = i * shardSize;var end = start + shardSize;var packet = file.slice(start, end); //将文件进行切片/* 构建form表单进行提交 */var form = new FormData();form.append("uuid", uuid);// 前端生成uuid作为标识符传个后台每个文件都是一个uuid防止文件串了form.append("data", packet); //slice方法用于切出文件的一部分form.append("name", name);form.append("totalSize", size);form.append("total", shardCount); //总片数form.append("index", i + 1); //当前是第几片$.ajax({url: "http://127.0.0.1:8080/index/doPost",type: "POST",data: form,//timeout:"10000", //超时10秒async: true, //异步dataType:"json",processData: false, //很重要,告诉jquery不要对form进行处理contentType: false, //很重要,指定为false才能形成正确的Content-Typesuccess: function (msg) {console.log(msg);/* 表示上一块文件上传成功,继续下一次 */if (msg.status === 201) {form = '';i++;PostFile(file, i, uuid);} else if (msg.status === 502) {form = '';/* 失败后,每2秒继续传一次分片文件 */setInterval(function () { PostFile(file, i, uuid) }, 2000);} else if (msg.status === 200) {merge(uuid, name)console.log("上传成功");} else if (msg.status === 500) {console.log('第'+msg.i+'次,上传文件有误!');} else {console.log('未知错误');}}})}function merge(uuid, fileName) {$.ajax({url: "http://127.0.0.1:8080/index/merge",type: "GET",data: {uuid: uuid, newFileName: fileName},//timeout:"10000", //超时10秒async: true, //异步dataType:"json",success: function (msg) {console.log(msg);}})}function guid() {return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function (c) {var r = Math.random() * 16 | 0,v = c === 'x' ? r : (r & 0x3 | 0x8);return v.toString(16);});}
script>
html>
后端代码:
import org.apache.commons.io.FileUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;@Controller
@RequestMapping("/index")
public class test_controller {private static final String fileUploadTempDir = "D:/portalupload/fileuploaddir";private static final String fileUploadDir = "D:/portalupload/file";@RequestMapping("/doPost")@ResponseBodypublic Map fragmentation(HttpServletRequest req, HttpServletResponse resp) {resp.addHeader("Access-Control-Allow-Origin", "*");Map map = new HashMap<>();MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) req;// 获得文件分片数据MultipartFile file = multipartRequest.getFile("data");
// 分片第几片int index = Integer.parseInt(multipartRequest.getParameter("index"));
// 总片数int total = Integer.parseInt(multipartRequest.getParameter("total"));
// 获取文件名String fileName = multipartRequest.getParameter("name");String name = fileName.substring(0, fileName.lastIndexOf("."));String fileEnd = fileName.substring(fileName.lastIndexOf("."));
// 前端uuid,作为标识String uuid = multipartRequest.getParameter("uuid");File uploadFile = new File(fileUploadTempDir + "/" + uuid, uuid + name + index + ".tem");if (!uploadFile.getParentFile().exists()) {uploadFile.getParentFile().mkdirs();}if (index < total) {try {file.transferTo(uploadFile);// 上传的文件分片名称map.put("status", 201);return map;} catch (IOException e) {e.printStackTrace();map.put("status", 502);return map;}} else {try {file.transferTo(uploadFile);// 上传的文件分片名称map.put("status", 200);return map;} catch (IOException e) {e.printStackTrace();map.put("status", 502);return map;}}}@RequestMapping(value = "/merge", method = RequestMethod.GET)@ResponseBodypublic Map merge(String uuid, String newFileName) {System.out.println(newFileName);Map retMap = new HashMap();try {File dirFile = new File(fileUploadTempDir + "/" + uuid);if (!dirFile.exists()) {throw new RuntimeException("文件不存在!");}//分片上传的文件已经位于同一个文件夹下,方便寻找和遍历(当文件数大于十的时候记得排序用冒泡排序确保顺序是正确的)String[] fileNames = dirFile.list();String name = newFileName.substring(0, newFileName.lastIndexOf("."));Arrays.sort(fileNames, (o1,o2)->{int i1 = Integer.parseInt(o1.substring(o1.indexOf(name)+name.length()).split("\\.tem")[0]);int i2 = Integer.parseInt(o2.substring(o2.indexOf(name)+name.length()).split("\\.tem")[0]);return i1 - i2;});// 创建空的合并文件File targetFile = new File(fileUploadDir, newFileName);if (!targetFile.getParentFile().exists()) {targetFile.getParentFile().mkdirs();}RandomAccessFile writeFile = new RandomAccessFile(targetFile, "rw");long position = 0;for (String fileName : fileNames) {System.out.println(fileName);File sourceFile = new File(fileUploadTempDir + "/" + uuid, fileName);RandomAccessFile readFile = new RandomAccessFile(sourceFile, "rw");int chunksize = 1024 * 3;byte[] buf = new byte[chunksize];writeFile.seek(position);int byteCount;while ((byteCount = readFile.read(buf)) != -1) {if (byteCount != chunksize) {byte[] tempBytes = new byte[byteCount];System.arraycopy(buf, 0, tempBytes, 0, byteCount);buf = tempBytes;}writeFile.write(buf);position = position + byteCount;}readFile.close();FileUtils.deleteQuietly(sourceFile);//删除缓存的临时文件}writeFile.close();retMap.put("code", "200");}catch (IOException e){e.printStackTrace();retMap.put("code", "500");}return retMap;}
}
测试:

可以看到文件进行了分片上传,我是上传了一个系统镜像文件,4GB多,上传的也是非常的快。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
