• 上传大文件的解决方案


    众所皆知,web上传大文件,一直是一个痛。上传文件大小限制,页面响应时间超时.这些都是web开发所必须直面的。

    本文给出的解决方案是:前端实现数据流分片长传,后面接收完毕后合并文件的思路。下面贴出简易DEMO源码分享:

    前端页面:

    @{

        ViewBag.Title = "Upload";

    }

    <h2>Upload</h2><table class="table table-striped">

        <tr>

            <td><input type="file" id="file"  onchange="selfile()" /></td>

            <td><input type="button" value="上传" onclick="uploading()"/></td>

        </tr>

        <tr>

            <td colspan="2">文件信息:<span id="fileMsg"></span></td>

        </tr>

        <tr>

            <td colspan="2">当前进度:<span id="upsize"></span></td>

        </tr></table><script src="~/Scripts/myUploader.js"></script><script type="text/javascript">

       //guid

        var guid = "@Guid.NewGuid()";

        var uploader;

        function selfile() {

            var f =  $("#file")[0].files[0];

            uploader = new SupperUploader("@Url.Action("RecvUpload")", f, guid, (1024*1024));

            $("#fileMsg").text("文件名:" + uploader.fileName + "文件类型:" + uploader.fileType + "文件大小:" + uploader.fileSize + "字节");

        }

        function uploading() {

            uploader.UploadFun(function () {

                $("#upsize").text(uploader.upedSize);

            })

        }</script>

    SupperUploader是我自己封装的JS插件,源码如下:

     var SupperUploader = function (uploadUrl, file, guid, cutSize) {

        this.file = file;

        //文件大小

        this.fileSize = file.size;

        //文件类型

        this.fileType = file.type;

        //文件路径

        this.fileName = file.name;

        //guid

        this.guid = guid;

        //分片大小

        this.cutSize = cutSize,

        //已上传

        this.upedSize = 0;

        //开始位置

        this.startIndex = 0;

        //结束位置

        this.endIndex = 0;

        //序号

        this.indexr = 0;

        //上传路径

        this.uploadUrl = uploadUrl;

        //合并结果

        this.merged = false;

    };

    SupperUploader.prototype = {

        UploadFun: function (uploadCallBack) {

            if (this.merged)

                return;

            var thisobj = this;

            $.ajax({

                type: "POST",

                url: thisobj.uploadUrl,

                enctype: 'multipart/form-data',

                data: thisobj.CutFileFun(),

                processData: false,

                contentType: false,

                success: function (res) {

                    if (res == "success") {

                        if (thisobj.upedSize == thisobj.fileSize) {

                            thisobj.merged = true;

                            alert("已成功上传!")

                            return;

                        }

                        thisobj.upedSize += thisobj.cutSize;

                        if (thisobj.upedSize > thisobj.fileSize)

                            thisobj.upedSize = thisobj.fileSize;

                        thisobj.indexr+=1;

                        //执行回调函数                    uploadCallBack();

                        //继续调用上传                    thisobj.UploadFun(uploadCallBack);

                    }

                }

            });

        },

        CutFileFun: function () {

            var formData = null;

            if (this.upedSize < this.fileSize) {

                this.startIndex = this.upedSize;

                this.endIndex = this.startIndex + this.cutSize;

                if (this.endIndex > this.fileSize) {

                    this.endIndex = this.fileSize;

                }

                var currentData = this.file.slice(this.startIndex, this.endIndex);

                formData = new FormData();

                formData.append("file", currentData);

                formData.append("index", this.indexr);

                formData.append("fname", this.fileName);

                formData.append("guid", this.guid);

                formData.append("ismerge", this.fileSize == this.endIndex);

               

            }

            return formData;

        }

    };

    后端代码,此Demo是基于MVC架构的:

     

            [HttpGet]

            public ActionResult Upload() {

                return View();

            }

     

            [HttpPost]

            public ActionResult RecvUpload(){

                try

                {

                    string fileName = Request["fname"];

                    string index = Request["index"];

                    string guid = Request["guid"];

                    var file = Request.Files[0];

                    var ismerge = Request["ismerge"];

                    string tempDirpath = "~/Content/temp/" + guid + "/";

                    string savepath = tempDirpath + index + "_" + fileName;

                    //合并文件

                    if (bool.Parse(ismerge))

                    {

                        //获取所有分割文件

                        var files = System.IO.Directory.GetFiles(Server.MapPath(tempDirpath));

                        //文件FILEINFO

                        var infos = files.Select(x => new FileInfo(x)).ToList().OrderBy(x=>x.LastWriteTime).ToList();

                        //合并文件流

                        FileStream mergefs = new FileStream(Server.MapPath("~/Content/temp/" + fileName),FileMode.Append);

                        BinaryWriter bw = new BinaryWriter(mergefs);

                        FileStream tempfs = null;

                        BinaryReader tempbr= null;

                        infos.ToList().ForEach(f =>

                        {

                            tempfs = new FileStream(f.FullName, FileMode.Open);

                            tempbr = new BinaryReader(tempfs);

                            bw.Write(tempbr.ReadBytes((int)tempfs.Length));

                            tempfs.Close();

                            tempbr.Close();

                        });

                        bw.Close();

                        mergefs.Close();

                        //删除分块文件

                        infos.ForEach(f =>{

                            System.IO.File.Delete(f.FullName);

     

                        });

                        return Json("success");

                    }

                    if (!System.IO.Directory.Exists(Server.MapPath(tempDirpath))){

                        System.IO.Directory.CreateDirectory(Server.MapPath(tempDirpath));

                    }

                    using (FileStream fs = new FileStream(Server.MapPath(savepath), FileMode.CreateNew))

                    {

     

                        using (Stream stream = file.InputStream)

                        {

                            byte[] buffer = new byte[stream.Length];

                            stream.Read(buffer, 0, (int)stream.Length);

                            fs.Write(buffer, 0, buffer.Length);

                        }

                    }

                    return Json("success");

     

                }

                catch (Exception e)

                {

     

                    return Json(e.Message);

                }

               

            }

    在此分享!希望多多指正~

    后端代码逻辑大部分是相同的,目前能够支持MySQL,Oracle,SQL。在使用前需要配置一下数据库,可以参考我写的这篇文章:http://blog.ncmem.com/wordpress/2019/08/07/java超大文件上传与下载/

  • 相关阅读:
    使用sequelize-auto生成sequelize的Models
    table中td内容过长自动换行
    编写一个方法,去掉数组的重复元素
    call, apply的用法意义以及区别是什么
    在javascript中使用媒体查询media query
    总结的一些封装好的javascript函数
    只对safari起作用的css hack
    javascrip实现无缝滚动
    Ensures there will be no 'console is undefined' errors
    jQuery.isEmptyObject()函数用于判断指定参数是否是一个空对象。
  • 原文地址:https://www.cnblogs.com/xproer/p/11346452.html
Copyright © 2020-2023  润新知