简单文件分块上传 c#后台

vue code

<style>
    .upload_warp_img_div_del {
        position: absolute;
        top: 6px;
        width: 16px;
        right: 4px;
    }

    .upload_warp_img_div_top {
        position: absolute;
        top: 0;
        width: 100%;
        height: 30px;
        background-color: rgba(0, 0, 0, 0.4);
        line-height: 30px;
        text-align: left;
        color: #fff;
        font-size: 12px;
        text-indent: 4px;
    }

    .upload_warp_img_div_text {
        white-space: nowrap;
        width: 80%;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    .upload_warp_img_div img {
        max-width: 100%;
        max-height: 100%;
        vertical-align: middle;
    }

    .upload_warp_img_div {
        position: relative;
        /*height: 100px;
        width: 120px;*/
        border: 1px solid #ccc;
        margin: 0px 30px 10px 0px;
        float: left;
        line-height: 100px;
        display: table-cell;
        text-align: center;
        background-color: #eee;
        cursor: pointer;
    }

    .upload_warp_img {
        border-top: 1px solid #D2D2D2;
        padding: 14px 0 0 14px;
        overflow: hidden;
    }

    .upload_warp_text {
        text-align: left;
        margin-bottom: 10px;
        padding-top: 10px;
        text-indent: 14px;
        border-top: 1px solid #ccc;
        font-size: 14px;
    }

    .upload_warp_right {
        float: left;
        width: 57%;
        margin-left: 2%;
        height: 100%;
        border: 1px dashed #999;
        border-radius: 4px;
        line-height: 130px;
        color: #999;
    }

    .upload_warp_left img {
        margin-top: 32px;
    }

    .upload_warp_left {
        /*float: left;
        width: 40%;*/
        height: 100%;
        border: 1px dashed #999;
        border-radius: 4px;
        cursor: pointer;
        text-align:center;
    }

    .upload_warp {
        margin: 14px;
        height: 130px;
    }

    .upload {
        border: 1px solid #ccc;
        background-color: #fff;
        /*width: 650px;*/
        box-shadow: 0px 1px 0px #ccc;
        border-radius: 4px;
    }

    .hello {
        width: 400px;
        /*margin-left: 34%;*/
    }
style>
<div class="page-container" id="RoundRobinOperate">

    <div class="row cl">
        <label class="form-label col-xs-4 col-sm-2">文件:label>
        <div class="formControls col-xs-8 col-sm-9">
            <div class="hello">
                <label class="" style="color:red;" v-show="error_tips['ImgFile']!=''"><sup>*sup>{{error_tips['ImgFile']}}label>
                <div class="upload">
                    <div class="upload_warp">
                        <div class="upload_warp_left" @@click="fileClick('ImgFile')" @@drop="drop($event,'ImgFile')" @@dragenter="dragenter($event)" @@dragover="dragover($event)">
                            <img src="@Url.Content("~/Content/img/upload.png")"><br />點擊或將文件拖到此處
                        div>
                    div>
                    <div class="upload_warp_text">{{bytesToSize(temp_ImgFile['ImgFile'].size)}}
                    div>
                    <input @@change="fileChange($event,'ImgFile')" type="file" id="ImgFile" accept="image/png, image/jpeg, image/gif, image/jpg" style="display: none" />
                    <div class="upload_warp_img" v-show="temp_ImgFile['ImgFile'].url!=''">
                        <div class="upload_warp_img_div">
                            <div class="upload_warp_img_div_top">
                                <div class="upload_warp_img_div_text">
                                    {{temp_ImgFile['ImgFile'].progress}} {{temp_ImgFile['ImgFile'].name}}
                                div>
                                <img src="@Url.Content("~/Content/img/del.png")" class="upload_warp_img_div_del" @@click="fileDel('ImgFile')">
                            div>
                            <img :src="temp_ImgFile['ImgFile'].url">
                        div>
                    div>
                div>
                <button @@Click="readFile('ImgFile')" class="btn btn-primary radius" type="button"><i class="Hui-iconfont">i> 上傳button>
            div>
        div>
    div>

div>

<script type="text/javascript">
    var _uploadFileUrl = "@Url.Content("~/RoundRobin/uploadFile")";
    var _root_path = "@Url.Content("~/")";
    $(function () {
        _vue_RoundRobinOperate = new Vue({
            el: "#RoundRobinOperate",
            name: "RoundRobinOperate",
            data: function () {
                return {
                     root_path: _root_path
                    , temp_ImgFile: { ImgFile: { url: "", size: 0, progress: "", name: "" }, ImgFileTra: { url: "", size: 0, progress: "", name: "" }, ImgFileSimp: { url: "", size: 0, progress: "", name: "" } }
                    , error_tips: { ImgFile: "", ImgFileTra: "", ImgFileSimp :"",submit:""}

                    , imgList: {}
                    , transmission_dataS:{}
                };
            },
            created: function () {

            },
            methods: {
                fileClick(lang) {
                    document.getElementById(lang).click();
                },
                fileChange(el, lang) {
                    if (!el.target.files[0].size) return;
                    this.fileAdd(el.target.files[0], lang);
                    el.target.value = ''
                },
                fileAdd(file, lang) {
                    //判断是否为图片文件 不属于图片文件的话,给一个默认图片作为预览图
                    if (file.type.indexOf('image') == -1) {
                    let _this = this;
                        _this.temp_ImgFile[lang] = { url:"@Url.Content("~/Content/img/wenjian.png")", size: file.size, progress: "未上傳", name: file.name };
                        _this.imgList[lang] = file;
                            } else {
                        let reader = new FileReader();
                        let _this = this;
                        reader.readAsDataURL(file);
                        reader.onload = function () {
                            _this.temp_ImgFile[lang] = { url: this.result, size: file.size, progress: "未上傳", name: file.name };
                            _this.imgList[lang] = file;
                        }
                    }
                },
                fileDel(lang) {
                    this.temp_ImgFile[lang] = { url: "", size: 0, progress: "", name: "" };
                    delete this.imgList[lang];
                },
                bytesToSize(bytes) {
                    if (bytes === 0) return '0 B';
                    let k = 1000, // or 1024
                      sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
                      i = Math.floor(Math.log(bytes) / Math.log(k));
                    return (bytes / Math.pow(k, i)).toPrecision(3) + ' ' + sizes[i];
                },
                dragenter(el) {
                    el.stopPropagation();
                    el.preventDefault();
                },
                dragover(el) {
                    el.stopPropagation();
                    el.preventDefault();
                },
                drop(el, lang) {
                    el.stopPropagation();
                    el.preventDefault();
                    this.fileAdd(el.dataTransfer.files[0], lang);
                },


                uploadFile: function (pack, lang) {
                    axios.post(_uploadFileUrl, { "data": pack }).then(function (response) {
                        var obj = response.data;
                        if (obj.type == 0 || obj.type == 1) {
                            var pct = ((parseFloat(_vue_RoundRobinOperate.transmission_dataS[obj.packId].packIndex + 1) / parseFloat(_vue_RoundRobinOperate.transmission_dataS[obj.packId].packCount)) * 100).toFixed(2);
                            _vue_RoundRobinOperate.temp_ImgFile[lang].progress = "上傳中 " + pct + "%";
                            //console.log(pct + "%");
                        }
                        if (obj.type == 0) {
                            var transmission_data = _vue_RoundRobinOperate.transmission_dataS[obj.packId];
                            transmission_data.packIndex = obj.packIndex;
                            if (transmission_data.packIndex < transmission_data.packCount - 1) {
                                _vue_RoundRobinOperate.sendPack(1, transmission_data, lang);
                            } else {
                                _vue_RoundRobinOperate.sendPack(2, transmission_data, lang);
                            }
                        } else if (obj.type == 1) {
                            _vue_RoundRobinOperate.temp_ImgFile[lang].progress = "上傳成功";
                            if (lang == "ImgFile") {
                                _vue_RoundRobinOperate.round_robin.ImgFile = obj.fileUrl;
                            } else if (lang == "ImgFileTra") {
                                _vue_RoundRobinOperate.round_robin.ImgFileTra = obj.fileUrl;
                            } else if (lang == "ImgFileSimp") {
                                _vue_RoundRobinOperate.round_robin.ImgFileSimp = obj.fileUrl;
                            }

                            delete _vue_RoundRobinOperate.transmission_dataS[obj.packId];
                        }
                        else if (obj.type == 2) {
                            var transmission_data = _vue_RoundRobinOperate.transmission_dataS[obj.packId];
                            transmission_data.packIndex = obj.packIndex;
                            _vue_RoundRobinOperate.sendPack(2, transmission_data, lang);
                        }
                    }).catch(function (error) {
                        console.info(error);
                        setTimeout(function () {
                            _vue_RoundRobinOperate.uploadFile(pack, lang);
                        }, 5000);
                    });
                },
                readFile: function (lang) {
                    var file = this.imgList[lang];//input.files[0];
                    var query = {};
                    var chunks = [];
                    var chunk = 1 * 1024 * 1024;   //每片大小
                    if (!!file) {
                        this.error_tips[lang] = "";
                        var temp0 = file.name.split('.');
                        var _extension = temp0[temp0.length - 1];
                        var start = 0;
                        //文件分片
                        for (var i = 0, len1 = Math.ceil(file.size / chunk) ; i < len1 ; i++) {
                            var end = start + chunk;
                            chunks[i] = file.slice(start, end);
                            start = end;
                        }

                        var packid = parseInt(Math.random() * 10000) + new Date().getTime();
                        this.transmission_dataS[packid] = {
                            packCount: chunks.length,
                            packIndex: 0,
                            packId: packid,
                            dataExtension: _extension,
                            dataBuffer: chunks
                        };
                        //console.log("file.name -》");
                        this.temp_ImgFile[lang].progress = "開始上傳";
                        this.sendPack(0, this.transmission_dataS[packid], lang);
                    } else {
                        this.error_tips[lang] = "請選擇文件,然後再點上傳";
                    }
                },
                sendPack: function (type, transmission_data, lang) {
                    var reader = new FileReader();
                    reader.readAsDataURL(transmission_data.dataBuffer[transmission_data.packIndex]);
                    reader.onload = function (e) {
                        //Type_Count_Id_Index_Data_key_extension
                        //Type 0-包开始 1-包传输中 2-包结束
                        //key MD5(Type+Count+Id+Index)
                        var Count = transmission_data.packCount;
                        var Index = transmission_data.packIndex;
                        var Id = transmission_data.packId;
                        var data = this.result;
                        var Type = type;
                        var key = Type + Count + Id + Index;
                        var extension = transmission_data.dataExtension;
                        var pack = Type + "_" + Count + "_" + Id + "_" + Index + "_" + data + "_" + key + "_" + extension;
                        _vue_RoundRobinOperate.uploadFile(pack, lang);
                    }
                }
            }
        });
    });
script>

c# 后台代码

//定义全局变量
public ActionResult index()
        {
            if (System.Web.HttpContext.Current.Cache["MyDictionary"] == null)
            {
                ConcurrentDictionary<string, List> MyDictionary = new ConcurrentDictionary<string, List>();
                System.Web.HttpContext.Current.Cache["MyDictionary"] = MyDictionary;
            }
            return View();
        }

#region 上傳
        public class MyDictionaryValueModel
        {
            public string Id { get; set; }
            public string[] Data { get; set; }
            public int Index { get; set; }

        }
        public JsonResult uploadFile(string data)
        {
           //Type_Count_Id_Index_Data_key_extension
           //Type 0-包开始 1-包传输中 2-包结束
           //key MD5(Type+Count+Id+Index)
            string temp_folder = string.Empty;
            string upload_folder = CommonService.ConfigurationManagerService.RoundRobinManageFolder;
            string root = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
            try
            {
                string UserId = GeneralMethods.GetCurrent().LoginName;
                var dataArry = data.Split('_');
                if (dataArry.Length == 7)
                {
                    string Type = dataArry[0],
                        Count = dataArry[1],
                        Id = dataArry[2],
                        Index = dataArry[3],
                        Data = dataArry[4],
                        key = dataArry[5],
                        extension = dataArry[6];
                    ConcurrentDictionary<string, List> MyDictionary = (ConcurrentDictionary<string, List>)System.Web.HttpContext.Current.Cache["MyDictionary"];
                    if (Type == "0")
                    {
                        if (!MyDictionary.ContainsKey(UserId))
                        {
                            MyDictionary.TryAdd(UserId, new List());
                        }
                        MyDictionary[UserId].Add(new MyDictionaryValueModel { Id = Id, Data = new string[Convert.ToInt32(Count)], Index = 0 });
                    }

                    var ValueModel = MyDictionary[UserId].Where(d => d.Id == Id).FirstOrDefault();
                    ValueModel.Data[Convert.ToInt32(Index)] = "received";
                    //------ 把文件块 保存到临时文件夹
                    var btsdata = Convert.FromBase64String(Data.Split(',')[1]);
                    temp_folder = root + upload_folder + @"/"+Id;

                    if (!Directory.Exists(temp_folder))
                    {
                        Directory.CreateDirectory(temp_folder);
                    }
                    string file1 = temp_folder + @"/" + Index + "." + "temp";//文件块
                    using (FileStream fs = new FileStream(file1, FileMode.Create))
                    {
                        fs.Write(btsdata, 0, btsdata.Length);
                        fs.Close();
                    }
                    //------

                    if (Convert.ToInt32(Count) == 1 || Type == "2")
                    {
                        bool data_is_complete = true;
                        for (int i = 0, len = ValueModel.Data.Length; i < len; i++)
                        {
                            var tempdata = ValueModel.Data[i];
                            if (tempdata == null)
                            {
                                data_is_complete = false;
                                //通知客户端 重新发送丢失的包
                                return Json(new { type =2, packId =Id, packIndex =i}, JsonRequestBehavior.AllowGet);                               
                            }

                        }
                        if (data_is_complete)
                        {
                            string uploadDir = root + upload_folder;

                            if (!Directory.Exists(uploadDir))
                            {
                                Directory.CreateDirectory(uploadDir);
                            }
                            string file_name = upload_folder + @"/" + Guid.NewGuid().ToString("D") +"-"+ DateTime.Now.ToString("HHmmssfff") + "." + extension;
                            string file = root + file_name;
                            using (FileStream fs = new FileStream(file, FileMode.Create))
                            {//从临时文件夹,读取文件块,合并到同一个文件
                                for (int i = 0, len = Convert.ToInt32(Count); i < len; i++)
                                {
                                    string file2 = temp_folder + @"/" + i.ToString() + "." + "temp";
                                    var tempBytes = System.IO.File.ReadAllBytes(file2);
                                    fs.Write(tempBytes, 0, tempBytes.Length);
                                }
                                fs.Close();
                            }
                            DeleteFolder(temp_folder);//删除临时文件
                            Directory.Delete(temp_folder, true);//删除临时文件夹

                            MyDictionary[UserId].Remove(ValueModel);
                            return Json(new { type = 1, packId = Id,fileUrl= file_name }, JsonRequestBehavior.AllowGet);
                        }
                    }
                    else
                    {
                        //通知客户端 已接收到
                        ValueModel.Index++;
                        return Json(new { type = 0, packId = Id ,packIndex = ValueModel.Index }, JsonRequestBehavior.AllowGet);
                    }
                }
            }
            catch (Exception ex)
            {
                if (temp_folder != string.Empty)
                {
                    DeleteFolder(temp_folder);
                    Directory.Delete(temp_folder, true);
                }
                //throw ex;
                JsonResult result = new JsonResult();
                result.MaxJsonLength = int.MaxValue;
                result.Data = new { type = -1, message = ex.ToString() };
                return result;
            }
            return Json(new { type = -1, message = "param error" }, JsonRequestBehavior.AllowGet);
        }

        public void DeleteFolder(string dir)
        {
            System.Threading.Tasks.Parallel.ForEach(Directory.GetFileSystemEntries(dir), (d) => {
                try
                {
                    if (System.IO.File.Exists(d))
                    {
                        FileInfo fi = new FileInfo(d);
                        if (fi.Attributes.ToString().ToLower().IndexOf("readonly") != -1)
                            fi.Attributes = FileAttributes.Normal;
                        System.IO.File.Delete(d);//直接删除其中的文件  
                    }
                    else
                    {
                        DirectoryInfo d1 = new DirectoryInfo(d);
                        if (d1.GetFiles().Length != 0)
                        {
                            DeleteFolder(d1.FullName);////递归删除子文件夹
                        }
                        Directory.Delete(d);
                    }
                }
                catch
                {

                }
            });
            if (Directory.GetFileSystemEntries(dir).Length > 0)
            {
                DeleteFolder(dir);
            }
        }
        #endregion

注:
1.websocket、signalr同理可得
2.注意文件分块,每块的大小,不适宜太大,会受到传输限制,上传失败时,可以尝试调整大小,目前设置的是每块1M
3.欢迎拍砖,反正我也不改

你可能感兴趣的:(简单文件分块上传 c#后台)