• 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"}");
                }
            }

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

  • 相关阅读:
    LightDB/postgresql内置特性之访问oracle之oracle_fdw介绍
    Java系列 | Linux系统中运行JMeter脚本
    适合新手练习的python开源经典源码
    基于python的json和cvs格式转换
    基于python中librosa的声音混音实例解析
    基于python的多线程串口处理实例源码解析
    基于python的定时PC定时录音机实现
    python librosa 实例解析
    噪声分贝测试测量仪工作原理分析
    Python中的join()函数的用法实例分析
  • 原文地址:https://www.cnblogs.com/meiCode/p/5239354.html
Copyright © 2020-2023  润新知