WebUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件。

大文件上传

实现思路:

分片:按照自定义缓冲区大小,将大文件分成多个小文件片段。

断点续传:根据分片数量,给每个小文件通过循环起对应名称,当文件下载中断在续传时,判断小文件名称若存在则不存了,此时还需要判断文件若不是最后一个分片则大小为缓冲区固定大小,若没达到则证明小文件没传完需要重新传输。

合并:下载时通过线程池创建任务进行下载或上传、当判断最后一个分片传完时,调用合并方法,根据之前定义的文件名称顺序进行合并,肯能出现最后一个分片传完,之前分片未传完的情况,需要使用while循环进行判断,多文件未传输完,则等待一会继续判断。

大文件秒传:实际上是根据文件名称区一个唯一的md5值存储,传文件时进行判断,若存在则不传。

创建springboot项目,添加依赖

 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId></dependency><dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.1</version></dependency><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.4</version></dependency>
<!--        做断点下载使用--><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpcore</artifactId></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies>

编写测试环境看环境有没有搭建成功

@Controller
public class UploadController {@RequestMapping("/up")@ResponseBodypublic String upload(HttpServletRequest request, HttpServletResponse response){return "搭建成功";}
}

页面主要代码

<body>
<div id="upload-container"><span>上传</span>
</div>
<div id="upload-list"></div>
<button id="picker">点击上传</button>
</body>
<script>$('#upload-container').click(function (event){$("#picker").find('input').click();});var uploader = WebUploader.create({auto: true,swf : 'Uploader.swf', //swf文件路径server: 'http://localhost:8080/upload',dnd: '#upload-container',pick: '#picker',  //内部根据当前运行创建multiple: true,     //选择多个chunked: true,      //开启分片threads: 20,        //并发数method: 'POST',fileSizeLimit: 1024*1024*1024*10, //单个文件大小限制fileSingleSizeLimit: 1024*1024*1024,  //总文件大小fileVal: 'upload'});uploader.on("beforeFileQueued",function (file){console.log(file); //获取文件后缀});uploader.on('fileQueued',function (file){//选中文件要做的事console.log(file.ext);console.log(file.size);console.log(file.name);var html = '<div class="upload-item"><span>文件名:'+file.name+'</span><span data-file_id="'+file.id+'"class="btn-delete">删除</span><span data-file_id="'+file.id+'"class="btn-retry">重试</span><div class="percentage '+file.id+'" style="width: 0%;"></div></div>'$('#upload-list').append(html);uploader.md5File(file)  //给文件定义唯一的md5值,当再次上传相同文件时,就不用传了  大文件秒传实际上是没传,直接拷贝之前文件地址//显示进度.progress(function (percentage){console.log('Percentage:',percentage);})//完成.then(function (val){console.log('md5 result',val);});});

webUpload组件支持分片上传:利用多进程并发上传,将大文件拆分成一个一个的小文件,每一个小文件属于大文件的一个分片

断点续传实现:后端代码

@Controller
public class UploadController {private final static String utf8 = "utf-8";@RequestMapping("/up")@ResponseBodypublic void upload(HttpServletRequest request, HttpServletResponse response) throws Exception {response.setCharacterEncoding(utf8);//长传时候会有多个分片,需要记录当前为那个分片Integer schunk = null;//总分片数Integer schunks = null;//名字String name = null;//文件目录String path = "D:\\file";BufferedOutputStream os = null;try {//设置缓冲区大小  先读到内存里在从内存写DiskFileItemFactory factory = new DiskFileItemFactory();factory.setSizeThreshold(1024);factory.setRepository(new File(path));//解析ServletFileUpload upload = new ServletFileUpload(factory);//设置单个大小与最大大小upload.setFileSizeMax(5l*1024l*1024l*1024l);upload.setSizeMax(10l*1024l*1024l*1024l);List<FileItem> items = upload.parseRequest(request);for (FileItem item : items){if (item.isFormField()){//获取分片数赋值给遍量if ("chunk".equals(item.getFieldName())){schunk = Integer.parseInt(item.getString(utf8));}if ("chunks".equals(item.getFieldName())){schunks = Integer.parseInt(item.getString(utf8));}if ("name".equals(item.getFieldName())){name = item.getString(utf8);}}}//取出文件基本信息后for (FileItem item : items){if (!item.isFormField()){//有分片需要临时目录String temFileName = name;if (name != null){if (schunk != null){temFileName = schunk+"_"+name;}//判断文件是否存在File temfile = new File(path, temFileName);//断点续传  判断文件是否存在,若存在则不传if (!temfile.exists()){item.write(temfile);}}}}//文件合并  当前分片为最后一个就合并if (schunk != null && schunk.intValue()== schunks.intValue()-1){File tempFile = new File(path, name);os = new BufferedOutputStream(new FileOutputStream(tempFile));//根据之前命名规则找到所有分片for (int i = 0; i < schunks; i++) {File file = new File(path, i + "_" + name);//并发情况 需要判断所有  因为可能最后一个分片传完,之前有的还没传完while (!file.exists()){//不存在休眠100毫秒后在从新判断Thread.sleep(100);}//分片存在  读入数组中byte[] bytes = FileUtils.readFileToByteArray(file);os.write(bytes);os.flush();file.delete();}os.flush();}response.getWriter().write("上传成功");}finally {try {if (os != null){os.close();}}catch (IOException e){e.printStackTrace();}}}
}

文件分片下载服务端

@Controller
public class DownLoadController {private final static String utf8 = "utf-8";@RequestMapping("/down")public void downLoadFile(HttpServletRequest request, HttpServletResponse response) throws IOException {response.setCharacterEncoding(utf8);//定义文件路径File file = new File("D:\\File\\a.mp4");InputStream is = null;OutputStream os = null;try {//分片下载long fSize = file.length();//获取长度response.setContentType("application/x-download");String fileName = URLEncoder.encode(file.getName(),utf8);response.addHeader("Content-Disposition","attachment;filename="+fileName);//根据前端传来的Range  判断支不支持分片下载response.setHeader("Accept-Range","bytes");//获取文件大小response.setHeader("fSize",String.valueOf(fSize));response.setHeader("fName",fileName);//定义断点long pos = 0,last = fSize-1,sum = 0;//判断前端需不需要分片下载if (null != request.getHeader("Range")){response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);String numRange = request.getHeader("Range").replaceAll("bytes=","");String[] strRange = numRange.split("-");if (strRange.length == 2){pos = Long.parseLong(strRange[0].trim());last = Long.parseLong(strRange[1].trim());//若结束字节超出文件大小 取文件大小if (last>fSize-1){last = fSize-1;}}else {//若只给一个长度  开始位置一直到结束pos = Long.parseLong(numRange.replaceAll("-","").trim());}}long rangeLenght = last-pos+1;String contentRange = new StringBuffer("bytes").append(pos).append("-").append(last).append("/").append(fSize).toString();response.setHeader("Content-Range",contentRange);response.setHeader("Content-Lenght",String.valueOf(rangeLenght));os = new BufferedOutputStream(response.getOutputStream());is = new BufferedInputStream(new FileInputStream(file));is.skip(pos);//跳过已读的文件byte[] buffer = new byte[1024];int lenght = 0;//相等证明读完while (sum < rangeLenght){lenght = is.read(buffer,0, (rangeLenght-sum)<=buffer.length? (int) (rangeLenght - sum) :buffer.length);sum = sum+lenght;os.write(buffer,0,lenght);}System.out.println("下载完成");}finally {if (is!= null){is.close();}if (os!=null){os.close();}}}
}

客户端分片下载,指定固定文件

@RestController
public class DownloadClient {private final static long per_page = 1024l*1024l*50l;//分片存储临时目录 当分片下载完后在目录中找到文件合并private final static String down_path="D:\\File";//多线程下载ExecutorService pool =  Executors.newFixedThreadPool(10);//文件大小 分片数量 文件名称//使用探测 获取变量//使用多线程分片下载//最后一个分片下载完 开始合并@RequestMapping("/downloadFile")public String downloadFile() throws IOException {FileInfo fileInfo = download(0,10,-1,null);if (fileInfo!= null){long pages = fileInfo.fSize/per_page;for (int i = 0; i <= pages; i++) {pool.submit(new Download(i*per_page,(i+1)*per_page-1,i,fileInfo.fName));}}return "成功";}class Download implements Runnable{long start;long end;long page;String fName;public Download(long start, long end, long page, String fName) {this.start = start;this.end = end;this.page = page;this.fName = fName;}@Overridepublic void run() {try {FileInfo fileInfo = download(start,end,page,fName);} catch (IOException e) {e.printStackTrace();}}}//返回文件名 跟大小private FileInfo download(long start,long end,long page,String fName) throws IOException {//断点下载 文件存在不需要下载File file = new File(down_path, page + "-" + fName);//探测必须放行 若下载分片只下载一半就锻炼需要重新下载所以需要判断文件是否完整if (file.exists()&&page != -1&&file.length()==per_page){return null;}//需要知道  开始-结束 = 分片大小HttpClient client = HttpClients.createDefault();//httpclient进行请求HttpGet httpGet = new HttpGet("http://127.0.0.1:8080/down");//告诉服务端做分片下载httpGet.setHeader("Range","bytes="+start+"-"+end);HttpResponse response = client.execute(httpGet);String fSize = response.getFirstHeader("fSize").getValue();fName= URLDecoder.decode(response.getFirstHeader("fName").getValue(),"utf-8");HttpEntity entity = response.getEntity();//获取文件流对象InputStream is = entity.getContent();//临时存储分片文件FileOutputStream fos = new FileOutputStream(file);byte[] buffer = new byte[1024];//定义缓冲区int ch;while ((ch = is.read(buffer)) != -1){fos.write(buffer,0,ch);}is.close();fos.flush();fos.close();//判断是不是最后一个分片if (end-Long.valueOf(fSize)>0){//合并try {mergeFile(fName,page);} catch (Exception e) {e.printStackTrace();}}return new FileInfo(Long.valueOf(fSize),fName);}private void mergeFile(String fName, long page) throws Exception {//归并文件位置File file = new File(down_path, fName);BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(file));for (int i = 0; i <= page; i++) {File tempFile = new File(down_path, i + "-" + fName);//分片没下载或者没下载完需要等待while (!file.exists()||(i!=page&&tempFile.length()<per_page)){Thread.sleep(100);}byte[] bytes = FileUtils.readFileToByteArray(tempFile);os.write(bytes);os.flush();tempFile.delete();}File file1 = new File(down_path, -1 + "-null");file1.delete();os.flush();os.close();}//使用内部类实现class FileInfo{long fSize;String fName;public FileInfo(long fSize, String fName) {this.fSize = fSize;this.fName = fName;}}
}

大文件上传下载实现思路,分片、断点续传代码实现,以及webUpload组件相关推荐

  1. Java实现FTP批量大文件上传下载

    用Java实现FTP批量大文件上传下载 <iframe id="I0_1416224567509" style="margin: 0px; padding: 0px ...

  2. HTML5 批量大文件上传下载

    前言 文件上传是一个老生常谈的话题了,在文件相对比较小的情况下,可以直接把文件转化为字节流上传到服务器,但在文件比较大的情况下,用普通的方式进行上传,这可不是一个好的办法,毕竟很少有人会忍受,当文件上 ...

  3. 浏览器 批量大文件上传下载

    本人在2010年时使用swfupload为核心进行文件的批量上传的解决方案.见文章:WEB版一次选择多个文件进行批量上传(swfupload)的解决方案. 本人在2013年时使用plupload为核心 ...

  4. Java 使用 FTP 实现大文件上传下载

    Java 上传下载 1G 以上的文件可以通过 http 协议或 ftp 实现,但是 http 协议对文件上传大小有限制,而且还不稳定,因此这里使用 ftp 上传. ftp 上传方式有两种: 一.ASC ...

  5. java ftp 大文件_用Java实现FTP批量大文件上传下载(二)

    2上传下载 文件的上传可以分成多线程及单线程,在单线程情况下比较简单,而在多线程的情况下,要处理的事情要多点,同时也要小心很多.下面是net.sf.jftp.net.FtpConnection的上传h ...

  6. VUE 项目大文件上传下载解决方案

    之前仿造uploadify写了一个HTML5版的文件上传插件,没看过的朋友可以点此先看一下~得到了不少朋友的好评,我自己也用在了项目中,不论是用户头像上传,还是各种媒体文件的上传,以及各种个性的业务需 ...

  7. java批量上传文件_Java 批量大文件上传下载

    第一点:Java代码实现文件上传 FormFile file = manform.getFile(); String newfileName = null; String newpathname =  ...

  8. centos nfs java_CentOS下安装配置NFS并通过Java进行文件上传下载

    1:安装NFS (1)安装 yum install nfs-utils rpcbind (2)启动rpcbind服务 systemctl restart rpcbind.service 查看服务状态 ...

  9. php文件断点上传文件,php大文件上传支持断点上传

    一个php大文件上传案例,可以支持断点续传,暂不支持文件上传演示 难易:中级 下载资源 下载积分: 200 积分 /** * 配置文件(如果没有默认字样,说明默认值就是注释下的值) * 但是,on*( ...

  10. Asp.net2.0下的大文件上传服务器控件

    最近本来准备在Alisoft上做点东西玩,做的过程中,涉及到了文件上传.刚开始,准备在网上找几个用,发现国外好用的要钱,而国内的,开源的又不好用,所以决定自己也写一个,顺便以后赚点外快.我看了一下,这 ...

最新文章

  1. 懒人必备 |通过爬虫 筛选以及查看CSDN 满足相应积分的资源列表 简单好用
  2. html table运用方法,HTML Table caption用法及代码示例
  3. debian6更新网卡驱动
  4. 解决ajax获取不到按钮的id
  5. vue element 框架 自定义轮播图,点击上下翻图,并让图片居中
  6. java操作当前日期的年月日
  7. 计算机科学和建筑设计结合,智能化建筑中计算机科学与技术的应用
  8. @property 各个属性作用【使用时最需注意strong/weak类型】【补充部分内存知识】...
  9. ODrive踩坑(四)AS5047P-SPI绝对值磁编码器,不需每次上电校准无刷电机,直接上电可用
  10. eclipse+Maven安装和配置
  11. 读论文 + 总结 + 笔记
  12. CorelDRAWX4的VBA插件开发(六)录制宏与调试
  13. 怎样把pdf转换成word-多语言ocr支持
  14. maven 常用命令
  15. nodejs+vue+elementui企业考勤管理系统
  16. matlab求COPULA偏导,matlab note
  17. “基本系统设备”及“性能计数器”驱动无法安装问题解决
  18. Uber无模式数据存储
  19. superslide遇到jQuery(…).slide is not a function解决办法
  20. 错题本 (并查集) acwing 4084.号码牌

热门文章

  1. 趣味程序设计_打印日历
  2. 微信收款语音播报android,电脑微信收款语音播报软件下载
  3. ssm java当前项目路径_SSM项目中动态获取路径
  4. 电路原理 邱关源 第五版 课后习题答案 课后习题详解
  5. Honor V10 BKL-AL20 ROOT(Magisk方式)
  6. RS485应用电路及问题经验总结
  7. Java华容道小程序设计
  8. 代码review总结
  9. PRINCE2认证10大常见问题集锦,拿走不谢
  10. prince2 成功的项目管理_我的PRINCE2故事