资讯专栏INFORMATION COLUMN

关于大文件上传

shusen / 2424人阅读

关于大文件上传 思路

使用js读取form表单中选择的file,计算文件md5值,并上传md5值到服务端,检查文件是否已上传过(类似秒传功能)

若文件未上传过,按照其大小切成1MB大小的块,小于1MB的不用切

用ajax异步提交切好的块上传至服务端(一个块一个请求,不阻塞,多线程)

当上传完成所有切块,发起一个合并文件的请求,服务端进行前面上传的文件块的合并,合并完成即上传完成。

实现

js计算文件md5使用spark-md5.js,据说这个库使用的是世界上最快的md5算法。

js对文件切片并使用ajax上传切片:

let size = file.size; //获取文件大小
const shardSize = 1024 * 1024; // 块大小1MB
let shardCount = Math.ceil(size/shardSize); //可切成的块数

for(let i = 0; i < shardCount; i++){
  let start = i * shardSize,
      end = Math.min(size, start + shardSize);
  let form = new FormData();
  form.append("file", file.slice(start, end));  //用slice方法切片
  form.append("size", end - start);
  form.append("name", name);
  form.append("total", shardCount);
  form.append("md5", file_md5); //文件md5值
  form.append("index", i);  //第几块

  $.ajax({
    url: "upload.php?type=shard",
    type: "POST",
    data: form,
    // async: false,     //是否异步上传,默认true
    processData: false, //很重要,告诉jquery不要对form进行处理
    contentType: false, //很重要,指定为false才能形成正确的Content-Type
    success: function (res) {
      // 成功回调
    }
  }
}

php端保存切片

$path = __DIR__ . "/uploads";
$file = $_FILES["file"];
$total = $_POST["total"];
$index = $_POST["index"];
$size = $_POST["size"];
$dst_file = $path . "/" . $name . "-" . $total . ":" . $index;  // 切片文件存储的文件名 
if ($file["error"] > 0) {
    echo json_encode(["code"=>400, "msg"=>$file["error"]]);die;
} else {
    $res = move_uploaded_file($file["tmp_name"], $dst_file);
    if ($res) {
        file_put_contents($dst_file . ".info", $size);  // 切片上传成功,写一个保存其大小的文件,后续合并是校验文件用的到
        echo json_encode(["code"=>200, "msg"=>"shard ok"]);die;
    } else {
        echo json_encode(["code"=>400, "msg"=>"shard move_uploaded_file error"]);die;
    }
}

php端合并

function mergeFile($name, $total, &$msg)
{
    // 校验切片文件是否都上传完成,是否完整
    for ($i = 0; $i < $total; $i++) { 
        if (!file_exists($name . "-" . $total . ":" . $i . ".info") || !file_exists($name . "-" . $total . ":" . $i)) {
            $msg = "shard error $i";
            return false;
        } else if (filesize($name . "-" . $total . ":" . $i) != file_get_contents($name . "-" . $total . ":" . $i . ".info")) {
            $msg = "shard size error $i";
            return false;
        }
    }
    @unlink($name);
    if (file_exists($name . ".lock")) {   //加锁 防止有其他进程写文件,造成文件损坏
        $msg = "on lock";
        return false;
    }
    touch($name . ".lock");
    $file = fopen($name, "a+");
    for ($i = 0; $i < $total; $i++) {   //按切片顺序写入文件
        $shardFile = fopen($name . "-" . $total . ":" . $i, "r");
        $shardData = fread($shardFile, filesize($name . "-" . $total . ":" . $i));
        fwrite($file, $shardData);
        fclose($shardFile);
        unlink($name . "-" . $total . ":" . $i); 
        unlink($name . "-" . $total . ":" . $i . ".info");
    }
    fclose($file);
    unlink($name . ".lock");
    return true;
}

我也写好了一个demo,传送门

下面是这个demo的效果图:

这个demo有些方面还不够完善,后续持续完善吧~

原文连接:

关于大文件上传

更多分享知识点,请扫码关注微信公众号:

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/109785.html

相关文章

  • 关于文件上传

    showImg(https://segmentfault.com/img/bVbs1lu?w=675&h=221); 关于大文件上传 思路 使用js读取form表单中选择的file,计算文件md5值,并上传md5值到服务端,检查文件是否已上传过(类似秒传功能) 若文件未上传过,按照其大小切成1MB大小的块,小于1MB的不用切 用ajax异步提交切好的块上传至服务端(一个块一个请求,不阻塞,多线程...

    zollero 评论0 收藏0
  • 关于七牛云正确使用姿势探索

    摘要:,在后续测试时遇到一个诡异,当文件过大时,任务脚本上传到七牛云失败。当我遇到大文件无法上传到七牛云时,断点调试到这里,发现返回的是。后来还真被我找到了,七牛云官方提供一个脚本工具。 业务场景 需求 我们项目有一个文件上传需求,需要从客户端上传到七牛云的对象存储和自己的应用服务器上。这里使用七牛云主要是实现下载分发。应用服务器需要留一份是因为后续需要做文件分析(并且是上传后需要立马分析出...

    3fuyu 评论0 收藏0
  • 关于数据迁移,你应该知道的那些方法

    摘要:数据迁移过程中的速率问题。关闭源站数据迁移典型案例剖析七牛客户陌陌的数据量非常大,如果采用常用的传输办法,整个迁移过程要耗时半年,并且会严重影响线上的业务。为此,七牛为陌陌制定了个性化的数据迁移方案。 showImg(http://sharlyne-lee.qiniudn.com/m1.png); 无论是计划拥抱云服务还是打算从正在使用的云服务切换到另外一家,这其中数据的迁移是很关键...

    DDreach 评论0 收藏0
  • 关于前端上传文件全面基础扫盲贴(四) ----- FileReader

    摘要:没有浏览器测试,所以不知道是不是有效,其实里面看起来比我写的那个复杂,实际上多了个检验格式上兼容写法所以不要怕,如果我错了记得提醒下我啊。目前为止其实已经该说的都差不多覆盖到了吧,动手能力强的话已经可以根据教程写一个实例出来的了。 系列文章 关于前端上传文件全面基础扫盲贴(零)关于前端上传文件全面基础扫盲贴(一) ----- XMLHttpRequest关于前端上传文件全面基础扫盲贴(...

    Tony 评论0 收藏0
  • 关于chrome点击上传反应慢的问题

    摘要:文章出处最近项目中有一个文件上传的功能,可以上传压缩包文件,遇到一个问题,就是个别电脑点击上传控件时,需要四五秒左右才会有反应。由于我们请求不到海外服务器,会等到连接诶失败,才会弹出上传文件窗口。 文章出处:http://www.jianshu.com/p/be34... 最近项目中有一个文件上传的功能,可以上传压缩包文件,遇到一个问题,就是个别电脑点击上传控件时,需要四五秒左右才会有...

    toddmark 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<