背景:50G大文件的HTTP上传至服务器。

好了,根据这个命题,可以开始研究我们怎么做才能把这么大的文件上传成功。

分片上传是肯定的,断点续传也是要有的,进度可视化那就更好了,基于这些,我选择了Webuploader在前端进行分片上传。

为什么选择它呢,好吧,它简单,易上手,好排错,文档多......

实际是我懒......

网上的教程大部分是复制粘贴,借鉴起来也很无奈,推荐一个我觉得比较实在的

https://www.cnblogs.com/baiyunchen/p/5383507.html

本篇Demo地址,欢迎各位大佬指点

https://github.com/papapalh/Big_File

一:开始

新建立项目,这里用了php7.0版本后台处理。

没啥说的,下载WebUploader的包http://fex.baidu.com/webuploader/download.html

jQuery也是必须的,因为就是依赖jQ的。

好了,可以初始化我们的上传组件了,介绍一下这里Demo的配置

  1. // 创建上传
  2. var uploader = WebUploader.create({
  3. swf: '/webuploader-0.1.5/Uploader.swf',
  4. server: 'index.php', // 服务端地址
  5. pick: '#picker', // 指定选择文件的按钮容器
  6. resize: false,
  7. chunked: true, //开启分片上传
  8. chunkSize: 1024*1024*4, //每一片的大小
  9. chunkRetry: 100, // 如果遇到网络错误,重新上传次数
  10. threads: 3, //上传并发数。允许同时最大上传进程数。
  11. });
  1. // 上传提交
  2. $("#ctlBtn").click(function () {
  3. console.log('准备上传...');
  4. uploader.upload();
  5. });

二:上传分片

好了,这样看吧,一个文件会被切分成为若干个小片段发送到服务器中。

但是,我们之后要做的断点续传,如何以唯一的标识来记录这个文件呢。

用MD5吧,简单粗暴,我觉得肯定有更好的办法,但是由于是DEMO,先整体跑下来在说。

下面这段代码做了这些事

  1. 添加文件进来时计算文件的MD5,用于文件的唯一标识
  2. 检查之前有没有上传一半出问题的,如果出问题了,那么,以MD5命名的文件夹肯定会有,那么我们传之后的就好了。
  3. 我给这个状态绑定了一个参数Status
  1. // 当有文件被添加进队列的时候-md5序列化
    uploader.on('fileQueued', function (file) {
    console.log("正在计算MD5值...");
  2. uploader.md5File(file)
  3.  
  4. .then(function (fileMd5) {
  5. file.wholeMd5 = fileMd5;
  6. file_md5 = fileMd5;
  7. console.log("MD5计算完成。");
  8. console.log("正在查找有无断点...");
  9.  
  10. $.post('check.php', {md5: file_md5}, function (data) {
  11. data = JSON.parse(data);
  12. switch (data.code) {
  13. // 断点
  14. case '0':
  15. console.log('有断点.正在准备从断点处上传文件。');
  16. for (var i in data.block_info) {
  17. block_info.push(data.block_info[i]);
  18. }
  19. file.status = 0;
  20. break;
  21. // 无断点
  22. case '1':
  23. console.log('无断点.上传新文件。');
  24. file.status = 1;
  25. break;
  26. }
  27. })
  28. });
  29. });

check.php

检查有没有遗留的文件夹,有的话说明你之前上传过,这些我就不要了,并返回上传成功的分片 JSON

  1. <?php
  2. // 接收相关数据
  3. $post = $_POST;
  4.  
  5. // 找出分片文件
  6. $dir = '/var/www/'.$post['md5'];
  7.  
  8. // 有断点
  9. if (file_exists($dir)) {
  10. // 找出上传成功的所有文件
  11. $block_info=scandir($dir);
  12.  
  13. // 除去无用文件
  14. foreach ($block_info as $key => $block) {
  15. if ($block == '.' || $block == '..') unset($block_info[$key]);
  16. }
  17.  
  18. echo json_encode(["code"=>"0" , 'block_info' => $block_info]);
  19. }
  20. // 无断点
  21. else {
  22. echo json_encode(["code"=>"1"]);
  23. }

index.php

接受传入文件,写入临时文件,这里其实也应该用个MD5来检查分片

  1. <?php
  2. // 接收相关数据
  3. $post = $_POST;
  4. $file = $_FILES;
  5. $status = $post['status'];
  6.  
  7. // 建立临时目录存放文件-以MD5为唯一标识
  8. $dir = "/var/www/" . $post['md5value'];
  9.  
  10. // 断点上传
  11. if ($status == '0') {
  12. // 获取分片文件内容
  13. $block_info=scandir($dir);
  14. // 除去无用文件
  15. foreach ($block_info as $key => $block) {
  16. if ($block == '.' || $block == '..') unset($block_info[$key]);
  17. }
  18. }
  19. // 直接上传
  20. elseif($status == '1') {
  21. if (!file_exists($dir)) {
  22. mkdir ($dir,0777,true);
  23. }
  24.  
  25. // 移入缓存文件保存
  26. move_uploaded_file($file["file"]["tmp_name"], $dir.'/'.$post["chunk"]);
  27. }

三:断点.跳过已有分片

这个地方是困扰了我很长时间的地方

官方API对于跳过分片的内容也找不到,所以单独把他拿出来,日后也方便查看

刚刚我们把如果有断点的,我们把上传成功的分片数组拿出来,比对一下,如果有,就不上传了

  1. // 发送前检查分块,并附加MD5数据
  2. uploader.on('uploadBeforeSend', function( block, data ) {
  3. var file = block.file;
  4. var deferred = WebUploader.Deferred();
  5.  
  6. data.md5value = file.wholeMd5;
  7. data.status = file.status;
  8.  
  9. if ($.inArray(block.chunk.toString(), block_info) >= 0) {
  10. console.log("已有分片.正在跳过分片"+block.chunk.toString());
  11. deferred.reject();
  12. deferred.resolve();
  13. return deferred.promise();
  14. }
  15. });

这样就完成了我们对于断点和分片的处理

四:合并

首先你得告诉我,你上传完了,该合并了

  1. // 上传完成后触发
  2. uploader.on('uploadSuccess', function (file,response) {
  3. console.log("上传分片完成。");
  4. console.log("正在整理分片...");
  5. $.post('merge.php', { md5: file.wholeMd5, fileName: file.name }, function (data) {
  6. var object = JSON.parse(data);
  7. if (object.code) {
  8. console.log("上传成功");
  9. }
  10. });
  11. });

这是Webuploader它上传成功的一个回调

告诉了merge.php

让开吧,我要合并了,就这个意思吧

  1. <?php
  2. // 接收相关数据
  3. $post = $_POST;
  4.  
  5. // 找出分片文件
  6. $dir = '/var/www/'.$post['md5'];
  7.  
  8. // 获取分片文件内容
  9. $block_info = scandir($dir);
  10.  
  11. // 除去无用文件
  12. foreach ($block_info as $key => $block) {
  13. if ($block == '.' || $block == '..') unset($block_info[$key]);
  14. }
  15.  
  16. // 数组按照正常规则排序
  17. natsort($block_info);
  18.  
  19. // 定义保存文件
  20. $save_file = "/var/www/".$post['fileName'];
  21.  
  22. // 没有?建立
  23. if (!file_exists($save_file)) fopen($post['fileName'], "w");
  24.  
  25. // 开始写入
  26. $out = @fopen($save_file, "wb");
  27.  
  28. // 增加文件锁
  29. if (flock($out, LOCK_EX)) {
  30. foreach ($block_info as $b) {
  31. // 读取文件
  32. if (!$in = @fopen($dir.'/'.$b, "rb")) {
  33. break;
  34. }
  35.  
  36. // 写入文件
  37. while ($buff = fread($in, 4096)) {
  38. fwrite($out, $buff);
  39. }
  40.  
  41. @fclose($in);
  42. @unlink($dir.'/'.$b);
  43. }
  44. flock($out, LOCK_UN);
  45. }
  46. @fclose($out);
  47. @rmdir($dir);
  48.  
  49. echo json_encode(["code"=>"0"]);//随便返回个值,实际中根据需要返回

看着挺长,实际就一个意思,按顺序写入。

五:其他

特殊效果也加了一点,可以试试

  1. // 文件上传过程中创建进度条实时显示。
  2. uploader.on('uploadProgress', function (file, percentage) {
  3. $("#percentage_a").css("width",parseInt(percentage * 100)+"%");
  4. $("#percentage").html(parseInt(percentage * 100) +"%");
  5. });
  6.  
  7. // 上传出错处理
  8. uploader.on('uploadError', function (file) {
  9. uploader.retry();
  10. });
  11.  
  12. // 暂停处理
  13. $("#stop").click(function(e){
  14. log("暂停上传...");
  15. uploader.stop(true);
  16. })
  17.  
  18. // 从暂停文件继续
  19. $("#start").click(function(e){
  20. log("恢复上传...");
  21. uploader.upload();
  22. })

五:PS

  1. 其实需要做的还有很多,各种验证,一定要保证分片的正确上传和写入。
  2. 还有各种的错误处理,之后如果运用到项目中的话,也一定会回来补充需要注意的地方
  3. 作为这个知识领域的小白,感觉很奇妙,也很有意思。

六:展示效果

  可以对页面进行下改动,也挺漂亮了,感谢。

使用Webuploader大文件分片传输的更多相关文章

  1. Webuploader 大文件分片上传

    百度Webuploader 大文件分片上传(.net接收)   前阵子要做个大文件上传的功能,找来找去发现Webuploader还不错,关于她的介绍我就不再赘述. 动手前,在园子里找到了一篇不错的分片 ...

  2. 百度Webuploader 大文件分片上传(.net接收)

    前阵子要做个大文件上传的功能,找来找去发现Webuploader还不错,关于她的介绍我就不再赘述. 动手前,在园子里找到了一篇不错的分片上传的帖子,参考之后,踏出了第一步.此文记录我这次实践的点滴,仅 ...

  3. 百度Webuploader 大文件分片上传(.net接收)

    版权所有 2009-2018荆门泽优软件有限公司 保留所有权利 官方网站:http://www.ncmem.com/ 产品首页:http://www.ncmem.com/webapp/up6.2/in ...

  4. asp.net mvc+webuploader大文件分片上传

    首先是前端: var GUID = WebUploader.Base.guid();//一个GUID uploadereditsVideo = WebUploader.create({ // swf文 ...

  5. webuploader大文件分片,多线程总结

    项目的新需求是用webuploader来做一个多文件,多线程,并且可以进行分块上传的要求,这些在前面的一篇文章当中足够使用了,但是现在又来一个新的需求,要求上传失败的文件进行重新的上传……心里默默说句 ...

  6. ASP.NET CORE使用WebUploader对大文件分片上传,并通过ASP.NET CORE SignalR实时反馈后台处理进度给前端展示

    本次,我们来实现一个单个大文件上传,并且把后台对上传文件的处理进度通过ASP.NET CORE SignalR反馈给前端展示,比如上传一个大的zip压缩包文件,后台进行解压缩,并且对压缩包中的文件进行 ...

  7. .NetCore+WebUploader实现大文件分片上传

    项目要求通过网站上传大文件,比如视频文件,通过摸索实现了文件分片来上传,然后后台进行合并. 使用了开源的前台上传插件WebUploader(http://fex.baidu.com/webupload ...

  8. thinkphp+webuploader实现大文件分片上传

    大文件分片上传,简单来说就是把大文件切分为小文件,然后再一个一个的上传,到最后由这些小文件再合并成原来的文件 webuploader下载地址及其文档:http://fex.baidu.com/webu ...

  9. 在React中使用WebUploader实现大文件分片上传的踩坑日记!

    前段时间公司项目有个大文件分片上传的需求,项目是用React写的,大文件分片上传这个功能使用了WebUploader这个组件. 具体交互是: 1. 点击上传文件button后出现弹窗,弹窗内有选择文件 ...

随机推荐

  1. Harbor api 操作

    harbor 的版本为 1.5.2 为 Harbor 配置 swagger 官网参考: https://github.com/goharbor/harbor/blob/v1.5.2/docs/conf ...

  2. 1474 十进制转m进制

    1474 十进制转m进制  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 白银 Silver 题解       题目描述 Description 将十进制数n转换成m进制数 m ...

  3. PHP与.Net的区别(一)接口

    一.关于接口成员 PHP的接口成员只能包括两种: 1.函数签名 2.常量 .Net的接口成员只能包括三种: 1.函数签名 2.属性(注意:是属性,不是字段) 3.事件 4.索引器(也叫有参属性)

  4. docker第一章:docker核心概念及centos6下安装

    Docker三大核心概念 镜像 容器 仓库 镜像 docker镜像类似于虚拟机镜像,可以将它理解为一个面向Docker引擎的只读模板,包含了文件系统. 容器 1.容器是从镜像创建的应用运行实例,容器和 ...

  5. Google Chrome 下载&绿化&增强

    Chrome下载 Google Chrome 已经可以在线更新,虽然比较慢! 国内常用的更新地址有两处:chromedownloads 和 shuax(耍下): https://www.chromed ...

  6. 阿里SopHix热修复框架

    2015年以来,Android开发领域里对热修复技术的讨论和分享越来越多,同时也出现了一些不同的解决方案,如QQ空间补丁方案.阿里AndFix以及微信Tinker(Bugly sdk也集成Tikner ...

  7. JQuery实战中遇到的两个小问题$(document).ready() 、bind函数的参数传递问题

    一.$(document).ready() 与 window.onload的区别 1.执行时间 window.onload 必须等到页面内所有元素(包括图片 css js等)加载完毕后才会执行. $( ...

  8. 用python连接mysql失败总结

    所用环境:python3,pycharm2018.2.4 先用mysql创建用户并授予相关权限 在我用python连接mysql时,一直提示连接不上,报错原因就是,用户没有被给予相关权限,比如查询,插 ...

  9. CSS| 框模型-padding

    例子:

  10. Python交互模式下代码自动补全

    这个功能是以lib的形式提供的,配置写到home下的.pythonrc文件中, 并设置好环境变量让python启动时执行初始化: # ~/.pythonrc # enable syntax compl ...