js php java分片分段上传大文件

js php java分片分段上传大文件

js php java分片分段上传大文件

实际工作中我们会遇到文件上传的问题,那么普通的小文件没什么问题,很快,但是大文件就容易出现超时、网络堵塞等问题,传了一半会功亏一篑,比较烦人,还好h5支持file二进制文件api,所以可以很好地进行分片处理,将一个大文件分成需要小片段单独上传到服务器端,后台在所有分片上传完成后进行文件合并即可完成大文件的上传,而且由于分片上传是同步的,所有上传速度会更快。下面简单演示一下

js

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <title>HTML5大文件分片上传</title>
    <script src="http://repo.bfw.wiki/bfwrepo/js/jquery.17.js"></script>
    <script>
        var page = {
            init: function() {
                $("#upload").click(
                    $.proxy(this.upload, this))},
            upload: function() {
                var file = $("#file")[0].files[0],
                name = file.name,
                size = file.size,
                succeed = 0;
                var shardSize = 2*1024*1024; //上传分片大小2M
                var shardCount = Math.ceil(size/shardSize);
                for (var i = 0; i < shardCount; ++i) {
                    var start = i*shardSize, end = Math.min(size, start+shardSize);
                    var form = new FormData();
                    form.append("filedata", file.slice(start, end));
                    form.append("filename", name);
                    form.append("total", shardCount); form.append("index", i+1);
                    $.ajax({
                        url: "/Upload",
                        type: "POST",
                        data: form,
                        async: true,
                        processData: false,
                        contentType: false,
                        success: function() {
                            ++succeed;
                            if (succeed == shardCount) {
                                $("#output").text("恭喜上传完成");
                            } else {
                                $("#output").text(succeed+" / "+shardCount);
                            }


                        }

                    })

                }

            }

        };
        $(function() {
            page.init();

        });
    </script>
</head>
<body>
    <input type="file" id="file" /><button id="upload">上传</button><span id="output" style="font-size:12px">等待</span>
</body>

</html>

php端

<?php
$name = $_POST['filename'];
$total = intval($_POST['total']);
$index = intval($_POST['index']);
$file = $_FILES['filedata'];
$dir = "Upload";
$filename = $dir.'/'. $file['name'].'_'.$index;
if (move_uploaded_file($file['tmp_name'], $filename)) {
    if ($index == $total) {
        $blob = '';
        for ($i = 1; $i <= $this->$total; $i++) {
            $blob .= file_get_contents($dir.'/'. $name.'_'.$i);
        }
        file_put_contents($dir.'/'. $name, $blob);
        unlink($dir.'/'. $name.'_'.$i);

    }
    //返回是否成功,此处做了简化处理
    return json_encode(['err' => 0]);
}
?>

java端

[HttpPost]
public ActionResult Upload()
{
    //从Request中取参数,注意上传的文件在Requst.Files中
    string name = Request["filename"];
    int total = Convert.ToInt32(Request["total"]);
    int index = Convert.ToInt32(Request["index"]);
    var data = Request.Files["filedata"];
     
    //保存一个分片到磁盘上
    string dir = Server.MapPath("~/Upload");
    string file = Path.Combine(dir, name + "_" + index);
    data.SaveAs(file);
     
    //如果已经是最后一个分片,组合
    //当然你也可以用其它方法比如接收每个分片时直接写到最终文件的相应位置上,但要控制好并发防止文件锁冲突
    if(index == total)
    {
        file = Path.Combine(dir, name);
        var fs = new FileStream(file, FileMode.Create);
        for(int i = 1;i <= total;++i)
        {
            string part = Path.Combine(dir, name + "_" + i);
            var bytes = System.IO.File.ReadAllBytes(part);
            fs.Write(bytes, 0, bytes.Length);
            bytes = null;
            System.IO.File.Delete(part);
        }
        fs.Close();
    }
     
    //返回是否成功,此处做了简化处理
    return Json(new { Error = 0 });
}

上面的demo只是简单演示分片的逻辑,没有加入任何异常处理,还有就是同步上传还是异步上传的处理没做,后端分片校验和完整也没有实现,大家可以自己去实现一下。

{{collectdata}}

网友评论0