zoukankan      html  css  js  c++  java
  • 使用BackgroundWorker 实现文件下载、异步提示

    最近在做一个IIS日志分析的系统,由于日志文件是在服务器上,但是分析需要放到客户端进行(为了提高性能和安全性),第一步就是需要将日志文件从服务器上下载到客户机上,可以通过控制台程序实现些功能,并且这个下载过程应该是自动化的不需要人工干预。
         准备做一个可视化的WinForm界面,这就需要反映文件下载进度,要达到这个实时报告进度的功能,就需要进行异步操作,可以通过线程或BackgroundWorker 类去实现, 由于BackgroundWorker 类是.net2.0新增的组件类,所以就先通过一个小实例来体验一下BackgroundWorker的使用方法,以后面的文章中将会给出使用线程的方法。
         我们先来了解BackgroundWorker 类的基本功能:
         在单独的线程上执行操作,此类是.net2.0新增的类,在.net1.1上不能使用(只能使用线程实现相同功能)。如果有一个需要很长时间才能完成的操作,而且不希望用户界面中出现延迟,则可以使用BackgroundWorker类来在另一个线程上运行该操作。
         BackgroundWorker 类允许您在单独的专用线程上运行操作。耗时的操作(如下载和数据库事务)在长时间运行时可能会导致用户界面 (UI) 似乎处于停止响应状态。如果您需要能进行响应的用户界面,而且面临与这类操作相关的长时间延迟,则可以使用 BackgroundWorker 类方便地解决问题。
         若要在后台执行耗时的操作,请创建一个 BackgroundWorker ,侦听那些报告操作进度并在操作完成时发出信号的事件。可以通过编程方式创建 BackgroundWorker ,也可以将它从 “工具箱” 的 “组件” 选项卡中拖到窗体上。如果在 Windows 窗体设计器中创建 BackgroundWorker ,则它会出现在组件栏中,而且它的属性会显示在“属性”窗口中。
         若要设置后台操作,请为 DoWork 事件添加一个事件处理程序。在此事件处理程序中调用耗时的操作。若要启动该操作,请调用 RunWorkerAsync 。若要收到进度更新通知,请对 ProgressChanged 事件进行处理。若要在操作完成时收到通知,请对 RunWorkerCompleted 事件进行处理。
         说明:您必须非常小心,确保在 DoWork 事件处理程序中不操作任何用户界面对象。而应该通过 ProgressChanged 和 RunWorkerCompleted 事件与用户界面进行通信。BackgroundWorker 事件不跨 AppDomain 边界进行封送处理。请不要使用 BackgroundWorker 组件在多个 AppDomain 中执行多线程操作。 
         如果后台操作需要参数,请在调用 RunWorkerAsync 时给出参数。在 DoWork 事件处理程序内部,可以从 DoWorkEventArgs..::.Argument 属性中提取该参数。
         下面我们一起来看实现过程,若大家发现有不对的地方,请指导,可以到我的blog留言
          运行界面:

    核心代码:
    1. private   void  btn_down_Click( object  sender, EventArgs e)
    2.         {
    3.              //指示 是否报告进度更新
    4.             backgroundWorker1.WorkerReportsProgress =  true ;
    5.              //指示 是否支持异步取消
    6.             backgroundWorker1.WorkerSupportsCancellation =  true ;
    7.              //启动异步操作,并可以传递object参数,如"ready go",
    8.              //以便在BackgroundWorker的_DoWork事件中使用此参数e.Argument
    9.             backgroundWorker1.RunWorkerAsync( "ready go" );
    10.              this .btn_cancel.Enabled =  true ;
    11.              this .btn_down.Enabled =  false ;
    12.         }
    13.          private   void  btn_cancel_Click( object  sender, EventArgs e)
    14.         {
    15.              //取消异步操作
    16.              this .backgroundWorker1.CancelAsync();
    17.              this .btn_cancel.Enabled =  false ;
    18.              this .btn_down.Enabled =  true ;
    19.         }
    20. private   void  backgroundWorker1_DoWork( object  sender, DoWorkEventArgs e)
    21.         {
    22.              //获取BackgroundWorker对象.
    23.             BackgroundWorker worker = sender  as  BackgroundWorker;
    24.             
    25.             
    26.              //e.Argument获取启动异步操作(backgroundWorker1.RunWorkerAsync("ready go");)时传递的object。
    27.              object  obj = e.Argument; //可以进行其它操作......
    28.              //将下载结果分配给DoWorkEventArgs对象的Result属性(e.Result),
    29.              //以提供给BackgroundWorker的RunWorkerCompleted事件作为句柄。
    30.             e.Result = DownLoadLog(worker, e);
    31.         }
    32.          private   void  backgroundWorker1_ProgressChanged( object  sender, ProgressChangedEventArgs e)
    33.         {
    34.              //获取异步进度的百分比
    35.              this .progressBar1.Value = e.ProgressPercentage;
    36.              this .lbl_msg.Text =  string .Format( "下载已完成{0}%,{1}M/{2}M" , e.ProgressPercentage, (Math.Round( decimal .Parse(e.UserState.ToString()) / ( decimal )(1024 * 1024),2)).ToString(), _fileSize.ToString());
    37.         }
    38.          private   void  backgroundWorker1_RunWorkerCompleted( object  sender, RunWorkerCompletedEventArgs e)
    39.         {
    40.              // 首先,事件处理发生错误时,抛出异常
    41.              if  (e.Error !=  null )
    42.             {
    43.                 MessageBox.Show(e.Error.Message);
    44.             }
    45.              else   if  (e.Cancelled)
    46.             {
    47.                  // Next, handle the case where the user canceled the operation.
    48.                  // Note that due to a race condition in 
    49.                  // the DoWork event handler, the Cancelled
    50.                  // flag may not have been set, even though
    51.                  // CancelAsync was called.
    52.                  //其次,事件处理操作被用户取消。
    53.                  //注意:由于事件运行条件由DoWork事件控制,尽管CancelAsync()方法被触发,但是未被设置为Cancelled标记。
    54.                  this .lbl_msg.Text =  "下载被取消!" ;
    55.             }
    56.              else
    57.             {
    58.                  // Finally, handle the case where the operation 
    59.                  // succeeded.
    60.                  this .lbl_msg.Text =  bool .Parse(e.Result.ToString()) ?  "下载成功!"  :  "下载失败!" ;
    61.             }
    62.              // Enable the Start button.
    63.             btn_down.Enabled =  true ;
    64.              // Disable the Cancel button.
    65.             btn_cancel.Enabled =  false ;
    66.         }
    67.         
    68.          /// <summary>
    69.          /// 下载日志
    70.          /// </summary>
    71.          /// <param name="worker"></param>
    72.          /// <param name="e"></param>
    73.          private   bool  DownLoadLog(BackgroundWorker worker, DoWorkEventArgs e)
    74.         {
    75.              long  maxFileSize = ftp.GetFileSize(_remoteFileName);
    76.             _fileSize = Decimal.Round((( decimal )maxFileSize / ( decimal )1024) / ( decimal )1024, 2);
    77.              //ftp.Get()方法中包含进度的报告、进程的取消、文件下载操作
    78.              return  ftp.Get(_remoteFileName, _localFolder, _localFileName, maxFileSize, worker, e);
    79.         }

        只贴出触发报告进度的事件 

    1. while  ( true )
    2.             {
    3.                 iBytes = socketData.Receive(buffer, buffer.Length, 0);
    4.                 output.Write(buffer, 0, iBytes);
    5.                 nowGetBytes += ( long )iBytes;
    6.                  //进度
    7.                  int  percentComplete = ( int )(( float )nowGetBytes / ( float )maxFileNum * 100);
    8.                  if  (worker.CancellationPending) //用户取消下载
    9.                 {
    10.                     e.Cancel =  true ;
    11.                     usercancel =  true ;
    12.                      break ;
    13.                 }
    14.                  else
    15.                 {
    16.                     worker.ReportProgress(percentComplete, nowGetBytes.ToString());
    17.                 }
    18.                  if  (iBytes <= 0)
    19.                 {
    20.                      break ;
    21.                 }
    22.             }
  • 相关阅读:
    docker国内镜像地址
    springBoot+websocket集群系列知识
    多个idea项目使用同一个tomcat
    nginx+tomcat遇到的https重定向到http问题
    设置常用错误页面自定义显示
    mysql关于索引的一些零碎知识点(持续更新)
    Idea使用Lombok简化实体类代码
    mysql索引分类及实现原理
    使用SpringSession和Redis解决分布式Session共享问题
    HashMap ConcurrentHashMap解读
  • 原文地址:https://www.cnblogs.com/jordan2009/p/1628569.html
Copyright © 2011-2022 走看看