web端大文件上传-webUploader

时间 2018/3/12 19:39:47 加载中...


视频说明


最近得项目中涉及到文件上传,且是大文件上传,6G,10G等。


于是找到百度得 webUploader,研究了一下再 .NET ASP.NET MVC 下得使用。

webUploader 支持 html5和flash两种文件上传形式,但最终研究,像10G这样得大文件,使用flash也是不行得。

所以必须使用html5得形式。 且支持断点续传。


直接上代码


HTML端:

<div id="uploader" class="wu-example">
    <!--用来存放文件信息-->
    <div id="thelist" class="uploader-list"></div>
    <div class="btns">
        <div id="picker">选择文件</div>        
    </div>

    <div id="item1">
        <p class="state">信息...</p>
    </div>
</div>


JS脚本:

<script>
    if (!WebUploader.Uploader.support()) {
        alert('Web Uploader 不支持您的浏览器!如果你使用的是IE浏览器,请尝试升级 flash 播放器');
        throw new Error('WebUploader does not support the browser you are using.');
    }
    @{ var path = Request.ApplicationPath == "/" ? "" : Request.ApplicationPath;}
    var g_appPath = '@path';
    var swfUrl = g_appPath + '/Scripts/webuploader-0.1.4/dist/Uploader.swf';
    var uploadChunkUrl = "@Url.Action("UploadChunk")";
    var checkChunkUrl = "@Url.Action("CheckChunk")";
    var mergeChunksUrl = "@Url.Action("MergeChunks")";
    var singleFileMaxSize = 4000;//单位:M

    var GUID = WebUploader.Base.guid();//一个GUID

    //监听分块上传过程中的三个时间点
    WebUploader.Uploader.register({
        "before-send-file": "beforeSendFile",
        "before-send": "beforeSend"
    }, {
        //时间点1:所有分块进行上传之前调用此函数
        beforeSendFile: function (file) {
            var deferred = WebUploader.Deferred();
            //1、计算文件的唯一标记,用于断点续传
            (new WebUploader.Uploader()).md5File(file, 0, 10 * 1024 * 1024)
                .progress(function (percentage) {
                    $('#item1').find("p.state").text("正在读取文件信息...");
                })
                .then(function (val) {
                    GUID = val;
                    $('#item1').find("p.state").text("成功获取文件信息...");
                    //获取文件信息后进入下一步
                    deferred.resolve();
                });
            return deferred.promise();
        },
        //时间点2:如果有分块上传,则每个分块上传之前调用此函数
        beforeSend: function (block) {
            var deferred = WebUploader.Deferred();

            $.ajax({
                type: "POST",
                url: checkChunkUrl,
                async:false,
                data: {
                    //文件唯一标记
                    fileMd5: GUID,
                    //当前分块下标
                    chunk: block.chunk,
                    //当前分块大小
                    chunkSize: block.end - block.start
                },
                dataType: "json",
                success: function (response) {                    
                    if (response.ifExist) {
                        //分块存在,跳过
                        deferred.reject();
                    } else {
                        //分块不存在或不完整,重新发送该分块内容
                        deferred.resolve();
                    }
                }
            });

            this.owner.options.formData.guid = GUID;
            deferred.resolve();
            return deferred.promise();
        }
    });

    var uploader = WebUploader.create({
        // swf文件路径
        swf: swfUrl,
        // 文件接收服务端。
        server: uploadChunkUrl,
        pick: {
            id: '#picker',
            //label: '上传',
            //innerHTML: '上传',
            multiple: false
        },
        fileNumLimit: 1,
        runtimeOrder: "html5",
        //100M
        fileSingleSizeLimit: 1024 * 1024 * singleFileMaxSize,
        auto: true,
        chunked: true,//开始分片上传
        chunkSize: 1024 * 1024 * 2,//每一片的大小
        formData: {
            guid: GUID //自定义参数
        },
        //accept: {
        //    //限制上传文件为MP4
        //    extensions: 'mp4',
        //    mimeTypes: 'video/mp4',
        //}
    });

    uploader.on('fileQueued', function (file) {
        //uploader.upload();
        $('#item1').empty();
        $('#item1').html(
            '<div id="' + file.id + '" class="item">' +
                '<span class="info">' + file.name + '</span><div></div>' +
                '<span class="state">等待上传...</span>' +
                '<a class="upbtn" id="btn" onclick="stop()">[取消上传]</a>' +
            '</div>'
        );
    });
    // 文件上传成功
    uploader.on('uploadSuccess', function (file, response) {
        //合并文件
        $('#' + file.id).find('span.state').text('文件合并中...');
        $.post(mergeChunksUrl, { guid: GUID, fileName: file.name }, function (data) {
            if (data.r == 1) {
                $('#' + file.id).find('span.state').text('已上传');
            }
            else {
                alert(data.err);
            }
        });
    });
    // 文件上传过程中创建进度条实时显示。
    uploader.on( 'uploadProgress', function( file, percentage) {
        $('#item1').find('span.state').text('上传中 ' + Math.round(percentage * 100) + '%');
    });

    uploader.on('uploadError', function (file, reason) {
        $('#' + file.id).find('p.state').text('上传出错' + reason);
    });
    /**
     * 验证文件格式以及文件大小
     */
    uploader.on("error", function (type) {
        if (type == "Q_TYPE_DENIED") {
            $('#item1').html("请上传JPG、PNG、GIF、BMP格式文件");
        } else if (type == "Q_EXCEED_SIZE_LIMIT") {
            $('#item1').html("文件大小不能超过");
        } else if (type == "F_EXCEED_SIZE") {
            $('#item1').html("文件大小不能超过" + singleFileMaxSize + "M");
        }
        else {
            $('#item1').html("上传出错!请检查后重新上传!错误代码" + type);
        }

    });

    uploader.on( 'uploadComplete', function( file ) {
        $( '#'+file.id ).find('.progress').fadeOut();
    });

    function start(){
        uploader.upload();
        $('#btn').attr("onclick","stop()");
        $('#btn').text("取消上传");
    }

    function stop(){
        uploader.stop(true);
        $('#btn').attr("onclick","start()");
        $('#btn').text("继续上传");
    }
</script>


控制器部分:

public class WebUploader2Controller : Controller
{
    // GET: WebUploader
    public ActionResult Index()
    {
        return View();
    }

    public ActionResult UploadChunk()
    {
        //如果进行了分片
        if (Request.Form.AllKeys.Any(m => m == "chunk"))
        {
            //取得chunk和chunks
            int chunk = Convert.ToInt32(Request.Form["chunk"]);//当前分片在上传分片中的顺序(从0开始)
            int chunks = Convert.ToInt32(Request.Form["chunks"]);//总分片数
            //根据GUID创建用该GUID命名的临时文件夹
            string folder = Server.MapPath("~/upload/" + Request["guid"] + "/");
            string path = folder + chunk;

            //建立临时传输文件夹
            if (!Directory.Exists(Path.GetDirectoryName(folder)))
            {
                Directory.CreateDirectory(folder);
            }

            FileStream addFile = new FileStream(path, FileMode.Append, FileAccess.Write);
            BinaryWriter AddWriter = new BinaryWriter(addFile);
            //获得上传的分片数据流
            var file = Request.Files[0];
            Stream stream = file.InputStream;

            BinaryReader TempReader = new BinaryReader(stream);
            //将上传的分片追加到临时文件末尾
            AddWriter.Write(TempReader.ReadBytes((int)stream.Length));
            //关闭BinaryReader文件阅读器
            TempReader.Close();
            stream.Close();
            AddWriter.Close();
            addFile.Close();

            TempReader.Dispose();
            stream.Dispose();
            AddWriter.Dispose();
            addFile.Dispose();
            return Json(new { chunked = true, hasError = false, f_ext = Path.GetExtension(file.FileName) });
        }
        else//没有分片直接保存
        {
            Request.Files[0].SaveAs(Server.MapPath("~/upload/" + DateTime.Now.ToFileTime() + Path.GetExtension(Request.Files[0].FileName)));
            return Json(new { chunked = true, hasError = false });
        }
    }

    public ActionResult MergeChunks()
    {
        try
        {
            var guid = Request["guid"];//GUID
            var uploadDir = Server.MapPath("~/upload");//Upload 文件夹
            var dir = Path.Combine(uploadDir, guid);//临时文件夹
            if (Directory.Exists(dir))
            {
                var ext = Path.GetExtension(Request["fileName"]);
                var files = Directory.GetFiles(dir);//获得下面的所有文件
                var name = Guid.NewGuid().ToString("N") + ext;
                var finalPath = Path.Combine(uploadDir, name);//最终的文件名
                var fs = new FileStream(finalPath, FileMode.Create);
                foreach (var part in files.OrderBy(x => x.Length).ThenBy(x => x))//排一下序,保证从0-N Write
                {
                    var bytes = System.IO.File.ReadAllBytes(part);
                    fs.Write(bytes, 0, bytes.Length);
                    bytes = null;
                    System.IO.File.Delete(part);//删除分块
                }
                fs.Flush();
                fs.Close();
                Directory.Delete(dir);//删除文件夹
                return Json(new { r = 1, path = "/upload/" + name });
            }
            else
            {
                return Json(new { r = 1, path = "" });
            }
        }
        catch (Exception ex)
        {
            return Json(new { r = 0, err = ex.Message });
        }
    }

    //检查当前分块是否上传成功 
    public ActionResult CheckChunk(string fileMd5, string chunk, string chunkSize)
    {
        string folder = Server.MapPath("~/upload/" + fileMd5 + "/");
        string path = folder + chunk;
        FileInfo checkFile = new FileInfo(folder + chunk);

        //检查文件是否存在,且大小是否一致  
        if (checkFile.Exists && checkFile.Length == int.Parse(chunkSize))
        {
            return Json(new { ifExist = 1 });
        }
        else
        {
            //没有上传过  
            return Json(new { ifExist = 0 });
        }
    }
}


此demo放在了github上,地址为:https://github.com/shenqiangbin/uploadFile


扫码分享
版权说明
作者:SQBER
文章来源:http://blog.sqber.com/articles/big-file-upload.html
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。