zoukankan      html  css  js  c++  java
  • 多线程文件分片上传

    文件上传方法

    /// <summary>
        /// 上传公共类
        /// </summary>
        public class UploadFile
        {
            #region 变量
            /// <summary>
            /// 起始位置
            /// </summary>
            long Begin;
            /// <summary>
            /// 结束位置
            /// </summary>
            long End;
            /// <summary>
            /// 每次上传的容量
            /// </summary>
            long size;
    
            /// <summary>
            /// 下载文件的大小
            /// </summary>
            public long FileSize;
            
            public string FileUrl;
    
            /// <summary>
            /// 是否暂停线程
            /// </summary>
            bool isRunning = true;
    
            //下载状态
            private UploadStatus status;
    
            /// <summary>
            /// 每次下载容量
            /// </summary>
            long DownloadCapacity;
    
            /// <summary>
            /// 下载已耗时
            /// </summary>
            private TimeSpan useTime;
    
            /// <summary>
            /// 最后一次下载时间
            /// </summary>
            private DateTime lastStartTime;
    
            /// <summary>
            /// 预计下载总耗时
            /// </summary>
            private TimeSpan allTime;
    
            /// <summary>
            /// 上一秒时已下载总大小
            /// </summary>
            private long BeforSecondUploadSize;
    
            /// <summary>
            /// 已下载大小
            /// </summary>
            private long UploadSize = 0;
    
            /// <summary>
            /// 当前下载速度
            /// </summary>
            private double speed;
            /// <summary>
            /// 是否上传完毕
            /// </summary>
            bool iscomplete = false;
    
            System.Timers.Timer t = new System.Timers.Timer();
    
            Task task;
            CancellationTokenSource cancelTokenSource = new CancellationTokenSource();
    
            public string parentFolderId { get; set; }
            /// <summary>
            /// 任务ID
            /// </summary>
            public string taskID { get; set; }
            /// <summary>
            /// 任务文档ID
            /// </summary>
            public string taskDocId { get; set; }
            /// <summary>
            /// 通用文档树文件夹ID
            /// </summary>
            public string folderId { get; set; }
            /// <summary>
            /// 通用文档根节点ID(第一级目录)
            /// </summary>
            public string docListId { get; set; }
            /// <summary>
            /// 上传或者更新文件类型,0为:作业文档;1为:通用文档;2为:问题文档;3为:工作流文档
            /// </summary>
            public int docType { get; set; }
            /// <summary>
            /// 上传类型,0为:上传;1为:更新
            /// </summary>
            public int opType { get; set; }
    
            UplpadDetectionFileDto detectionDto = new UplpadDetectionFileDto();
            #endregion
    
            #region 启动上传
            /// <summary>
            /// 启动上传
            /// </summary>
            /// <param name="UploadUrl">上传的URL</param>
            /// <param name="DetectionUrl">检测文件的URL</param>
            public void Startup(string UploadUrl, string DetectionUrl, UplpadDetectionFileDto DetectionDto)
            {
                if (this.status == UploadStatus.Idle)
                {
                    MessageUtil.ShowError("只有空闲中才能上传!");
                    return;
                }
                //与webapi通信,传递文件信息
                UplpadDetection Detection = WebCommunication.JsonRequestServiceToObject<UplpadDetection>(DetectionUrl, DetectionDto, CommonInfo.Ticike);
                if (Detection.rsCode == "S10000")
                {
                    if (Detection.Isexist == true)
                    {
                        Begin = Detection.StartingValue;
                    }
                    else
                    {
                        Begin = 0;
                    }
                }
                else
                {
                    MessageUtil.ShowError(ExceptionCode.GetCodeByExceptionInfo(Detection.rsCode));
                }
    
                t.Interval = 1000;
                t.Elapsed -= new System.Timers.ElapsedEventHandler(t_Elapsed);
                t.Elapsed += new System.Timers.ElapsedEventHandler(t_Elapsed);
                t.Start();
                detectionDto = DetectionDto;
                BeginUpload(UploadUrl, DetectionDto.FileGuid, DetectionDto.ActiomId, DetectionDto.FileName);
            }
    
            void t_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
            {
                OnUpload();
    
                if (iscomplete)
                {
                    isRunning = false;
                    t.Elapsed -= new System.Timers.ElapsedEventHandler(t_Elapsed);
                    t.Enabled = false;
                    //t.Close();
                    UploadSuccessDto Successdto = new UploadSuccessDto();
                    Successdto.fileGuid = detectionDto.FileGuid;
                    Successdto.fileName = detectionDto.FileName;
                    Successdto.proj_id = CommonInfo.ProjectId;
                    Successdto.taskID = taskID;
                    Successdto.taskDocId = taskDocId;
                    Successdto.parentFolderId = parentFolderId;
                    Successdto.folderId = folderId;
                    Successdto.docListId = docListId;
                    Successdto.docType = docType;
                    Successdto.opType = opType;
                    Successdto.userId = CommonInfo.UserGrid;
    
                    string successUrl = BaseClass.GetUrl("Upload", "UploadSuccess");
                    BaseDto dto = WebCommunication.JsonRequestServiceToObject<BaseDto>(successUrl, Successdto, CommonInfo.Ticike);
                    if (dto.rsCode == "S10000")
                    {
                        string sql = "UPDATE DownloadFileLocally set IsSuccess=1 where ActiomId='" + detectionDto.ActiomId + "'";
                        if (SQLiteOperation.UpdataSQlite(sql, null) > 0)
                        {
                            DownloadFileService.UpdateFileListComplete(detectionDto.ActiomId);
                            t.Elapsed -= new System.Timers.ElapsedEventHandler(t_Elapsed);
                            uploadComplete(true, "UploadComplete", detectionDto.FileGuid);
                            return;
                        }
                    }
                    else
                    {
                        string errorinfo=ExceptionCode.GetCodeByExceptionInfo(dto.rsCode);
                        MessageUtil.ShowError(detectionDto.FileName + ":" + errorinfo);
                        string sql = "UPDATE DownloadFileLocally set IsSuccess=2,ErrorInfo='" + errorinfo + "' where ActiomId='" + detectionDto.ActiomId + "'";
                        SQLiteOperation.UpdataSQlite(sql, null);
                        t.Elapsed -= new System.Timers.ElapsedEventHandler(t_Elapsed);
                        uploadComplete(true, "UploadComplete", detectionDto.FileGuid);
                        return;
                    }
                }
                //else { 
                //    if(Begin <= End)
                //}
            } 
            #endregion
    
            #region 上传暂停
            /// <summary>
            /// 上传暂停
            /// </summary>
            public void Pause()
            {
                if (this.status != UploadStatus.Uploading)
                {
                    MessageUtil.ShowError("只有上传中才能暂停!");
                    return;
                }
    
                // 后台线程会查看状态,如果状态时暂停的,
                // 下载将会被暂停并且状态将随之改为暂停.
                this.status = UploadStatus.Pausing;
    
                isRunning = false;
            } 
            #endregion
    
            #region 继续上传
            /// <summary>
            /// 继续上传
            /// </summary>
            public void Continue()
            {
                if (this.status != UploadStatus.Pausing)
                {
                    MessageUtil.ShowError("只有暂停状态才能继续上传!");
                    return;
                }
                this.status = UploadStatus.Uploading;
    
                isRunning = true;
            } 
            #endregion
    
            #region 取消上传
            ///<summary>
            ///取消上传
            ///</summary>
            public void Cancel(string FileGuid, string Uploadurl, string ActiomId, string FileName)
            {
                this.status = UploadStatus.Cancel;
                cancelTokenSource.Cancel();
                isRunning = false;
                size = DownloadCapacity * 1024;
                End = FileSize;
                UploadMethod(Uploadurl, DownloadCapacity, FileGuid, ActiomId, FileName, size, End,false);
    
    
            } 
            #endregion
    
            /// <summary>
            /// 重新上传
            /// </summary>
            public void Again(string UploadUrl, string DetectionUrl, UplpadDetectionFileDto DetectionDto)
            {
                this.status = UploadStatus.Cancel;
                cancelTokenSource.Cancel();
                isRunning = false;
                size = DownloadCapacity * 1024;
                End = FileSize;
                UploadMethod(UploadUrl, DownloadCapacity, DetectionDto.FileGuid, DetectionDto.ActiomId, DetectionDto.FileName, size, End, false);
    
                status = UploadStatus.Uploading;
                UplpadDetection Detection = WebCommunication.JsonRequestServiceToObject<UplpadDetection>(DetectionUrl, DetectionDto, CommonInfo.Ticike);
                if (Detection.rsCode == "S10000")
                {
                    if (Detection.Isexist == true)
                    {
                        Begin = Detection.StartingValue;
                    }
                    else
                    {
                        Begin = 0;
                    }
                }
                else
                {
                    MessageUtil.ShowError(ExceptionCode.GetCodeByExceptionInfo(Detection.rsCode));
                }
    
                t.Interval = 1000;
                t.Elapsed += new System.Timers.ElapsedEventHandler(t_Elapsed);
                t.Start();
                detectionDto = DetectionDto;
                BeginUpload(UploadUrl, DetectionDto.FileGuid, DetectionDto.ActiomId, DetectionDto.FileName);
            }
    
            #region 上传方法
            /// <summary>
            /// 多线程上传
            /// </summary>
            /// <param name="UploadUrl">上传URL</param>
            /// <param name="FileGuid">文件Guid</param>
            private void BeginUpload(string UploadUrl,string FileGuid,string ActiomId,string FileName)
            {
                try
                {
                    //获取线程数
                    EPMSDto.LocalData.DownloadConfiguration configuration = LocalDataDownloadConfiguration.GetDownloadConfigurationByUserName(CommonInfo.LoginName);
                    DownloadCapacity = configuration.DownloadCapacity;
                    ////计算出单次下载量
                    size = DownloadCapacity * 1024;
                    End = FileSize;
                    bool complete = false;
    
                    //遍历线程数(遍历几次就是启动几个线程)
                    for (int i = 0; i < configuration.ThreadNum; i++)
                    {
    //启动任务 task
    = Task.Factory.StartNew(() => UploadMethod(UploadUrl, DownloadCapacity, FileGuid, ActiomId, FileName, size, End, complete), cancelTokenSource.Token); Random rd = new Random(); int num= rd.Next(1500,2000); Thread.Sleep(num); } //UploadMethod(UploadUrl, DownloadCapacity, FileGuid, ActiomId, FileName); } catch (Exception ex) { LogHelper.WriteLog(typeof(DownLoadFile), ex); } } /// <summary> /// 上传方法 /// </summary> /// <param name="Uploadurl">上传的路径</param> /// <param name="DownloadCapacity">每次上传的大小(用户设置的)</param> /// <param name="startingValue"></param> public void UploadMethod(string Uploadurl, long DownloadCapacity, string FileGuid, string ActiomId, string FileName, long size, long End, bool complete) { //if (status != UploadStatus.Uploading) //{ // return; //} if (status == UploadStatus.Cancel) { t.Elapsed -= new System.Timers.ElapsedEventHandler(t_Elapsed); string deletesql = "delete from DownloadFileLocally where ActiomId='" + ActiomId + "'"; if (SQLiteOperation.UpdataSQlite(deletesql, null) == 0) { MessageUtil.ShowError("删除上传成功的文件记录出错!"); } DownloadFileService.DeleteFileList(ActiomId); WhereDto dt = new WhereDto(); dt.Where = FileGuid; string deleteurl = BaseClass.GetUrl("Upload", "CancelUpload"); BaseDto dto = WebCommunication.JsonRequestServiceToObject<BaseDto>(deleteurl, dt, CommonInfo.Ticike); uploadComplete(true, "UploadCancel", FileGuid); return; } while (End > Begin) { if (Begin < End) { if (!cancelTokenSource.IsCancellationRequested) { //下载保护 if (End - Begin < size) { size = End - Begin; if (size < 0) { size = 0; } //上传完成在这里写 //iscomplete = true; complete = true; } #region 上传

    //自旋锁(暂停上传) SpinWait.SpinUntil(() => isRunning); MyUploadFileDto Filedto = new MyUploadFileDto(); BeforSecondUploadSize = size; UploadSize = Begin; //文件信息 System.IO.FileStream readFs = new System.IO.FileStream(FileUrl, System.IO.FileMode.OpenOrCreate, FileAccess.Read, FileShare.ReadWrite); long lenth = readFs.Length; readFs.Position = Begin; byte[] filesize = new byte[size]; readFs.Read(filesize, 0, Convert.ToInt32(size)); readFs.Close(); //MD5加密 Filedto.FileMD5 = PasswordEncrypt.getMD5Hash(filesize); Filedto.ByteInfo = filesize; Filedto.StartingValue = Begin; Filedto.Uploadsize = size; Filedto.Guid = FileGuid; BaseDto dto = WebCommunication.JsonRequestServiceToObject<BaseDto>(Uploadurl, Filedto, CommonInfo.Ticike); if (dto.rsCode != "S10000") { MessageUtil.ShowError(ExceptionCode.GetCodeByExceptionInfo(dto.rsCode)); return; } iscomplete = complete; #endregion } } else { iscomplete = complete; } Begin += size; } if (End <= Begin) { iscomplete = true; } } #endregion #region 每秒信息事件方法 /// <summary> /// 更新下载所用时间 /// </summary> private void ChangeTime() { if (this.status == UploadStatus.Uploading) { DateTime now = DateTime.Now; if (now != lastStartTime) { useTime = useTime.Add(now - lastStartTime); lastStartTime = now; } } } public event UploadEventArgs.SecondUploadEventHandler SecondUploadEvent; /// <summary> /// 每秒信息方法 /// </summary> public void OnUpload() { if (SecondUploadEvent != null) { ChangeTime(); this.speed = (UploadSize - BeforSecondUploadSize) / 1024; long temp = 0; this.allTime = new TimeSpan(temp); int downLoadProportion = 0; if (UploadSize > 0) { downLoadProportion = Convert.ToInt32((Convert.ToDecimal(UploadSize) / Convert.ToDecimal(FileSize)) * 100); } else { downLoadProportion = 0; } UploadEventArgs.SecondUploadEventArgs e = new UploadEventArgs.SecondUploadEventArgs(UploadSize / 1024, useTime, allTime, speed, FileSize / 1024, downLoadProportion); SecondUploadEvent(this, e); } } #endregion #region 上传完成的事件方法 public event UploadEventArgs.UploadCompletedEventHandler UploadCompletedEvent; /// <summary> /// 上传完成的方法 /// </summary> /// <param name="isCompleted"></param> /// <param name="state"></param> /// <param name="Guid"></param> public void uploadComplete(bool isCompleted, string state, string Guid) { if (UploadCompletedEvent != null) { UploadEventArgs.UploadCompletedEvent e = new UploadEventArgs.UploadCompletedEvent(isCompleted, state, Guid); UploadCompletedEvent(this, e); } } #endregion }

    文件事件委托定义

    #region 委托类
        public class UploadEventArgs
        {
            /// <summary>
            ///  与每秒下载情况相关的委托
            /// </summary>
            /// <param name="sender">事件发起的对象</param>
            /// <param name="e">参数</param>
            public delegate void SecondUploadEventHandler(Object sender, SecondUploadEventArgs e);
            /// <summary>
            /// 下载完成的委托
            /// </summary>
            /// <param name="sender">事件发起的对象</param>
            /// <param name="e">参数</param>
            public delegate void UploadCompletedEventHandler(Object sender, UploadCompletedEvent e);
    
            /// <summary>
            /// 下载时每秒事件相关的参数
            /// </summary>
            public class SecondUploadEventArgs : EventArgs
            {
                /// <summary>
                /// 已下载大小
                /// </summary>
                public readonly long uploadSize;
    
                /// <summary>
                /// 下载已耗时
                /// </summary>
                public readonly TimeSpan useTime;
    
                //预计下载总耗时
                public readonly TimeSpan allTime;
    
                /// <summary>
                /// 当前下载速度
                /// </summary>
                public readonly double speed;
    
                /// <summary>
                /// 文件总大小
                /// </summary>
                public readonly long fileSize;
                /// <summary>
                /// 上传比例
                /// </summary>
                public readonly int uploadProportion;
    
                public SecondUploadEventArgs(long uploadSize, TimeSpan useTime, TimeSpan allTime, double speed, long fileSize, int uploadproportion)
                {
                    this.uploadSize = uploadSize;
                    this.useTime = useTime;
                    this.allTime = allTime;
                    this.speed = speed;
                    this.fileSize = fileSize;
                    uploadProportion = uploadproportion;
                }
            }
    
            /// <summary>
            /// 上传完成的
            /// </summary>
            public class UploadCompletedEvent : EventArgs
            {
                /// <summary>
                /// 是否完成
                /// </summary>
                public readonly bool UploadComplete;
                /// <summary>
                /// 上传状态
                /// </summary>
                public readonly string UploadState;
    
                public readonly string FileGuid;
                public UploadCompletedEvent(bool isComplete, string state, string Guid)
                {
                    UploadComplete = isComplete;
                    UploadState = state;
                    FileGuid = Guid;
                }
            }
    
        } 
        #endregion
    
        #region 上传状态枚举
        public enum UploadStatus
        {
            /// <summary>
            /// 下载
            /// </summary>
            Uploading,
            /// <summary>
            /// 
            /// </summary>
            Pausing,
            /// <summary>
            /// 空线
            /// </summary>
            Idle,
            /// <summary>
            /// 取消
            /// </summary>
            Cancel,
            /// <summary>
            /// 重新下载
            /// </summary>
            ReDownload,
            /// <summary>
            /// 完成下载
            /// </summary>
            Complete
        } 
        #endregion
    View Code

    WebAPI获取文件,保存文件

    /// <summary>
            /// 上传文件
            /// </summary>
            /// <param name="fileDto"></param>
            /// <returns></returns>
            public static BaseDto UploadFile(MyUploadFileDto fileDto)
            {
                BaseDto dto = new BaseDto();
                //获取到的文件转为MD5码
                string md5code=PasswordEncrypt.getMD5Hash(fileDto.ByteInfo);
                //判断文件转成的MD5码是否与传递来的MD5码一直,不一致则返回异常码信息
                if (md5code != fileDto.FileMD5) {
                    dto.rsCode = ErrorExceptionCode.ExceptionCode.UploadFile_MD5Error;
                    return dto;
                }
                //获取默认路径
                string Path = System.IO.Path.Combine(FileDownloadHandler.GetWebConfigureDocumentPath("DocumentLocation"));
                //判断默认路径是否存在,不存在则新建
                if (!Directory.Exists(Path))
                {
                    Directory.CreateDirectory(Path);
                }
                //组成保存文件的路径
                string address = System.IO.Path.Combine(Path, fileDto.Guid);
                //string address = @"E:\upload\" + fileDto.FileName;
                try
                {
                    //写入文件
                    using (FileStream _fs = new FileStream(address, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite))
                    {
                        //文件写入起始位置
                        _fs.Position = fileDto.StartingValue;
                        _fs.Write(fileDto.ByteInfo, 0, (int)fileDto.Uploadsize);
                        _fs.Flush();
                        _fs.Close();
                        _fs.Dispose();
                    }
                    dto.rsCode = ErrorExceptionCode.ExceptionCode.Success;
                }
                catch (Exception)
                {
                    dto.rsCode = ErrorExceptionCode.ExceptionCode.UploadFile_FileSaveError;
                }
                return dto;
            }
    View Code

    调用上传文件公共类

    UplpadDetectionFileDto fileDto=new UplpadDetectionFileDto();
                fileDto.FileName=UploadName;
                fileDto.FileGuid = FileGuid;
                fileDto.ActiomId = ActiomId;
                //实例化上传
                //UploadFile file = new UploadFile();
                file.docListId = docListId;
                file.docType = docType;
                file.folderId = folderId;
                file.opType = opType;
                file.parentFolderId = parentFolderId;
                file.taskDocId = taskDocId;
                file.taskID = taskID;
                file.FileSize = FileSize;
                file.FileUrl = FileUrl;
                //每一秒上传情况信息时间
                file.SecondUploadEvent += new UploadEventArgs.SecondUploadEventHandler(file_SecondUploadEvent);
                //上传完成的事件
                file.UploadCompletedEvent += new UploadEventArgs.UploadCompletedEventHandler(file_UploadCompletedEvent);
                //启动上传
                file.Startup(UploadUrl, DetectionUrl, fileDto);
    View Code
  • 相关阅读:
    批处理 windows service 的安装与删除
    HTML 页面元素介绍
    六 redis学习笔记之发布订阅
    发布个c#版的HandlerSocket客户端类库
    数据库单元测试
    一 redis学习笔记之环境搭建
    七 redis学习笔记之持久化
    三 redis学习笔记之排序
    四 redis学习笔记之事务
    元数据编程实战_使用Emit运行时生成Protobuf编码类
  • 原文地址:https://www.cnblogs.com/hyxf/p/5251864.html
Copyright © 2011-2022 走看看