zoukankan      html  css  js  c++  java
  • webUploader上传组件 实际运用小结

    WebUploader组件实际介绍:

    1. 官网:http://fex.baidu.com/webuploader/doc/index.html
    2. 组件优势及优化总结:http://itindex.net/detail/49267-webuploader-%E6%96%87%E4%BB%B6-%E4%B8%8A%E4%BC%A0
    3. 组件暂停功能的问题:https://github.com/fex-team/webuploader/issues/488
    4. 断点续传问题:https://github.com/fex-team/webuploader/issues/142
    5. 具体思路可以先参考链接:http://www.sxrczx.com/pages/blog.kazaff.me/uxgb1423648892626.html

    以下内容于你对上述组件有了大致了解的基础上,结合C#实现大文件的上传、断点续传、分块等功能,展开说明的:

    设计思路:在每次文件上传前,获取该文件的MD5值作为该文件的唯一标识符,然后对该文件进行分块处理(此处每块设置5M大小,详见2),按块分发请求(此处设置为3个线程发请求,详见2)文件开始上传前触发,一个文件只会触发一次 uploadStart事件,该事件会验证之前该文件是否已上传部分,返回已上传部分的块数编号列表,然后在下一个事件before-send(在文件分片处理之后,上传之前会触发)判断哪些块数已存在,上传不存在的文件块,至此基本上传流程已完成。

        /// <summary>
        /// 文件上传消息类
        /// </summary>
        public class UploaderResult
        {
            public UploaderResult()
            {
                this.IsOver = false;
                this.Chunk = 0;
                this.Chunks = 0;
                this.FileExtist = false;
                this.ChunkNum = new List<int>();
            }
    
            /// <summary>
            /// 文件名称、当上传完成时将返回最终的文件名
            /// </summary>
            public string Name { get; set; }
    
            /// <summary>
            /// 文件是否全部上传完成
            /// </summary>
            public bool IsOver { get; set; }
    
            /// <summary>
            /// 消息
            /// </summary>
            public string Message { get; set; }
    
            /// <summary>
            /// 如果为分块上传、返回当前的分块索引
            /// </summary>
            public int Chunk { get; set; }
    
            /// <summary>
            /// 总的分块大小
            /// </summary>
            public int Chunks { get; set; }
    
            /// <summary>
            /// 文件的MD5码
            /// </summary>
            public string Md5 { get; set; }
    
            /// <summary>
            /// 上传的文件是否已经存在于服务器
            /// </summary>
            public bool FileExtist { get; set; }
    
            /// <summary>
            /// 服务器已经存在的区块序号
            /// </summary>
            public List<int> ChunkNum { get; set; }
    
            /// <summary>
            /// 文件扩展名
            /// </summary>
            public string FileExtension { get; set; }
    
            /// <summary>
            /// 文件路径
            /// </summary>
            public string FilePath { get; set; }
    
            /// <summary>
            /// 文件大小
            /// </summary>
            public int FileSize { get; set; }
        }
            /// <summary>
            /// 断点续传检测、MD5检测 秒传亦可以在这个方法块中实现,看需求
            /// </summary>
            public static UploaderResult ProcessCheck(HttpRequestBase request, string savepath = null
                , Func<HttpPostedFileBase, string> setfilename = null, Func<string, bool> md5check = null)
            {
                UploaderResult obj = new UploaderResult();
                string tempFilePath = savepath + "temp\" + request["md5"] + "\";
              
                //文件大小
                long size = request.Form["size"] == null ? 0 : Convert.ToInt64(request.Form["size"]);
    
                //文件分块大小
                long chunksize = request.Form["chunksize"] == null ? 0 : Convert.ToInt64(request.Form["chunksize"]);
    
                //文件区块总数
                int chunks = chunksize != 0 ? Convert.ToInt32(size / chunksize) : 1;
                int j = 0;
                for (int i = 0; i <= chunks; i++)
                {
                    if (File.Exists(tempFilePath + i.ToString()))
                    {
                        obj.ChunkNum.Add(i);//服务器已经存在的区块编号
                        j++;
                    }
                }
                obj.Message = string.Format("服务器已经存在区块数量{0},总区块数量{1},占比{2}%", j
                    , chunks + 1, chunks != 0 && j != 0 ? Convert.ToDouble(Convert.ToDouble(j) / Convert.ToDouble(chunks)) * 100 : 0);
                return obj;
            }     
            /// <summary>
            /// 文件上传、保存
            /// </summary>
            /// <param name="request"></param>
            /// <param name="savepath"></param>
            /// <returns></returns>
            public static UploaderResult UploadSingleProcess(HttpRequestBase request, string savepath = null)
            {
                UploaderResult obj = new UploaderResult();
                if (request.Files.Count == 0)
                {
                    obj.Message = "请求中不包含文件流信息";
                    return obj;
                }
                if (request["size"] == null)
                {
                    obj.Message = "文件大小为空";
                    return obj;
                }
                string tempFilePath = savepath + "temp\" + request["md5"] + "\";
                string saveFilePath = savepath + "files\";
                if (!Directory.Exists(saveFilePath))
                {
                    Directory.CreateDirectory(saveFilePath);
                }
                //判断是否分片,若文件大小不足分片,则直接保存
                if (request.Form.AllKeys.Any(m => m == "chunk"))
                {
                    //分片时创建临时文件目录
                    if (!Directory.Exists(tempFilePath))    
                    {
                        Directory.CreateDirectory(tempFilePath);
                    }
                    //取得chunk和chunks
                    int chunk = Convert.ToInt32(request.Form["chunk"]);
                    int chunks = Convert.ToInt32(request.Form["chunks"]);
                    HttpPostedFileBase file = request.Files[0];
                    //根据GUID创建用该GUID命名的临时文件
                    file.SaveAs(tempFilePath + chunk.ToString());
                    //判断是否所有的分块都已经上传完毕
                    string[] fileArr = Directory.GetFiles(tempFilePath);
                    if (fileArr.Length == chunks) {
                        obj.IsOver = true;
                    }
                }
                else
                {
                    request.Files[0].SaveAs(saveFilePath + request.Files[0].FileName);
                    obj.IsOver = true;
                }
                return obj;
            }
            /// <summary>
            /// 文件块合并
            /// </summary>
            /// <returns></returns>
            public ActionResult MergeFiles()
            {
                string ext = Request.Form["fileExt"];
                string fileName = Request.Form["fileName"];
                string chunkNum = Request.Form["chunkNum"];
                string md5 = Request.Form["md5"];
                string tempFilePath = this.RootFolder + "\temp\" + md5 + "\";
                string saveFilePath = this.RootFolder + "\files\" + fileName;  
                string[] fileArr = Directory.GetFiles(tempFilePath);
                try
                {
                    lock (tempFilePath)
                    {
                        if (Convert.ToInt32(chunkNum) == fileArr.Length)
                        {
                            if (System.IO.File.Exists(saveFilePath))
                            {
                                System.IO.File.Delete(saveFilePath);
                            }
                            FileStream addStream = new FileStream(saveFilePath, FileMode.Append, FileAccess.Write);
                            BinaryWriter AddWriter = new BinaryWriter(addStream);
                            for (int i = 0; i < fileArr.Length; i++)
                            {
                                //以小文件所对应的文件名称和打开模式来初始化FileStream文件流,起读取分割作用
                                FileStream TempStream = new FileStream(tempFilePath+i, FileMode.Open);
                                //用FileStream文件流来初始化BinaryReader文件阅读器,也起读取分割文件作用
                                BinaryReader TempReader = new BinaryReader(TempStream);
                                //读取分割文件中的数据,并生成合并后文件
                                AddWriter.Write(TempReader.ReadBytes((int)TempStream.Length));
                                //关闭BinaryReader文件阅读器
                                TempReader.Close();
                                TempStream.Close();
                            }
                            AddWriter.Close();
                            addStream.Close();
                            AddWriter.Dispose();
                            addStream.Dispose();
                            Directory.Delete(tempFilePath, true);
                        }
                        //验证文件的MD5,确定文件的完整性 前端文件MD5值与后端合并的文件MD5值不相等
                        //if (UploaderHelper.GetMD5HashFromFile(saveFilePath) == md5)
                        //{
                        //    int i = 1;
                        //}
                        return Json("{hasError:"false"}");
                    }
                }
                catch (Exception ex)
                {
                    return Json("{hasError:"true"}");
                }
            }

    后台代码,还需要整理优化,当然如果有问题,大家可以一块学习谈论。

  • 相关阅读:
    tensorflow 2.0 学习 (十) 拟合与过拟合问题
    tensorflow 2.0 学习 (九) tensorboard可视化功能认识
    tensorflow 2.0 学习 (八) keras模块的认识
    tensorflow 2.0 学习 (七) 反向传播代码逐步实现
    tensorflow 2.0 学习 (六) Himmelblua函数求极值
    tensorflow 2.0 学习 (五)MPG全连接网络训练与测试
    arp协议简单介绍
    Pthread spinlock自旋锁
    线程和进程状态
    内核态(内核空间)和用户态(用户空间)的区别和联系·
  • 原文地址:https://www.cnblogs.com/meiCode/p/5239354.html
Copyright © 2011-2022 走看看