Board logo

标题: 【已解决】C# 异步读取文件任务,一次取消不了任务,需要多次才能取消任务 [打印本页]

作者: Gin_Q    时间: 2021-5-6 23:10     标题: 【已解决】C# 异步读取文件任务,一次取消不了任务,需要多次才能取消任务

本帖最后由 Gin_Q 于 2021-5-24 11:31 编辑

认真阅读这句话:请务必 将任务理解为工作的异步抽象,而非 在线程之上的抽象。 默认情况下,任务在当前线程上执行,且在适当时会将工作委托给操作系统。 可选择性地通过 Task.Run API  显式请求任务在独立线程上运行。
解决了。异步执行时,当前线程会收到终止异常。所以需要在当前线程中终止任务后,随后捕获异常(为新任务开始做好准备)。再开始新的任务!
  1. using System;
  2. using System.Drawing;
  3. using System.Threading;
  4. using System.IO;
  5. using System.Threading.Tasks;
  6. using System.Windows.Forms;
  7. public class Form1 : Form
  8. {
  9.     [STAThread]
  10.     public static void Main()
  11.     {
  12.         Application.EnableVisualStyles();
  13.         Application.Run(new Form1());
  14.     }
  15.     private readonly ProgressBar pbar;
  16.     private readonly Label label;
  17.     private readonly Button StartPausebut;
  18.     private readonly Button openFileBut;
  19.     private readonly Button Stopbut;
  20.     private readonly Button ShowHandle;
  21.     private readonly ListBox fileList;
  22.     private static CancellationTokenSource source = new CancellationTokenSource();
  23.     private readonly EventWaitHandle StartPausebutEventsynchro = new EventWaitHandle(false, EventResetMode.ManualReset);
  24.     private string selectFileName;
  25.     private string oldSelectFileName;
  26.     private Task task;
  27.     // 窗体
  28.     public Form1()
  29.     {
  30.         // 进度条
  31.         pbar = new ProgressBar();
  32.         pbar.Width = 500;
  33.         pbar.Location = new Point(10, 20);
  34.         pbar.Visible = true;
  35.         // 开始,暂停按键
  36.         StartPausebut = new Button();
  37.         StartPausebut.Text = "开始";
  38.         StartPausebut.Location = new Point(100, 60);
  39.         StartPausebut.Click += new EventHandler(StartPausebut_Click);
  40.         
  41.         // 上一个
  42.         Button selectUP = new Button();
  43.         selectUP.Text = "上一个";
  44.         selectUP.Location = new Point(10, 90);
  45.         selectUP.Click += new EventHandler(selectUP_Click);
  46.         // 下一个
  47.         Button selectDown = new Button();
  48.         selectDown.Text = "下一个";
  49.         selectDown.Location = new Point(100, 90);
  50.         selectDown.Click += new EventHandler(selectDown_Click);
  51.         // 取消按键
  52.         Stopbut = new Button();
  53.         Stopbut.Text = "终止读取";
  54.         Stopbut.Location = new Point(190, 60);
  55.         Stopbut.Click += new EventHandler(Stopbut_Click);
  56.         // 显示窗口句柄
  57.         ShowHandle = new Button();
  58.         ShowHandle.Text = "显示窗口句柄";
  59.         ShowHandle.Location = new Point(280, 60);
  60.         ShowHandle.Click += ShowHandle_Click;
  61.         // 选择文件状态
  62.         openFileBut = new Button();
  63.         openFileBut.Text = "选择文件";
  64.         openFileBut.Location = new Point(10, 60);
  65.         openFileBut.Click += new EventHandler(openFileBut_Click);
  66.         
  67.         // 加载文件列表
  68.         Button loadBut = new Button();
  69.         loadBut.Text = "加载文件列表";
  70.         loadBut.Width = 100;
  71.         loadBut.Location = new Point(370, 60);
  72.         loadBut.Click += new EventHandler(loadBut_Click);
  73.         // 提示信息标签
  74.         label = new Label();
  75.         label.Location = new Point(10, 120);
  76.         label.AutoSize = true;
  77.         
  78.         //文件列表内容
  79.         fileList = new ListBox();
  80.         fileList.Size = new System.Drawing.Size(500,400);
  81.         fileList.Location = new Point(10, 140);
  82.         fileList.MultiColumn = true;
  83.         this.Controls.Add(StartPausebut);
  84.         this.Controls.Add(pbar);
  85.         this.Controls.Add(label);
  86.         this.Controls.Add(Stopbut);
  87.         this.Controls.Add(openFileBut);
  88.         this.Controls.Add(ShowHandle);
  89.         this.Controls.Add(fileList);
  90.         this.Controls.Add(loadBut);
  91.         this.Controls.Add(selectUP);
  92.         this.Controls.Add(selectDown);
  93.         this.Width = 600;
  94.         this.Height = 600;
  95.     }
  96.     // 开始,暂停 按键事件
  97.     private void StartPausebut_Click(object sender, EventArgs e)
  98.     {
  99.         Application.DoEvents();
  100.         if (StartPausebut.Text == "开始")
  101.         {
  102.             StartPausebut.Text = "暂停";
  103.             StartPausebutEventsynchro.Set(); // 任务非阻塞状态
  104.             if (task == null || task.IsCompleted)
  105.             {
  106.                 oldSelectFileName = selectFileName;
  107.                 task = Task.Run(() => openFileStream());               
  108.             }
  109.             else if (selectFileName != oldSelectFileName)
  110.             {
  111.                 Stopbut_Click(this, new EventArgs());
  112.                 task = Task.Run(() => openFileStream());
  113.                 StartPausebut.Text = "暂停";
  114.             }
  115.             return ;
  116.         }
  117.         else if (StartPausebut.Text == "暂停")
  118.         {
  119.             StartPausebut.Text = "开始";
  120.             StartPausebutEventsynchro.Reset(); // 任务阻塞状态
  121.             return ;
  122.         }
  123.     }
  124.     // 选择文件
  125.     private void openFileBut_Click(object sender, EventArgs e)
  126.     {
  127.         // 选择文件对话框
  128.         OpenFileDialog dlg = new OpenFileDialog();
  129.         dlg.Filter = "Text documents (*.*)|*.*";
  130.         dlg.ShowDialog();
  131.         selectFileName = dlg.FileName;
  132.         label.Text = selectFileName;
  133.         if (selectFileName == "")
  134.         {
  135.             return;
  136.         }
  137.         
  138.     }
  139.     // 取消任务
  140.     private void Stopbut_Click(object sender, EventArgs e)
  141.     {
  142.         // if (!source.Token.IsCancellationRequested)
  143.         try
  144.         {
  145.             if (task.Status != TaskStatus.RanToCompletion)
  146.             {
  147.                 source.Cancel(); // 取消任务
  148.                 StartPausebutEventsynchro.Reset();
  149.                 Application.DoEvents();
  150.                 StartPausebutEventsynchro.Set();            
  151.             }
  152.             else
  153.             {
  154.                 return;
  155.             }            
  156.         }
  157.         catch {return;}
  158.         try
  159.         {
  160.             task.Wait();
  161.         }
  162.         catch
  163.         {
  164.             StartPausebut.Text = "开始";
  165.             source.Dispose();
  166.             source = new CancellationTokenSource(); //重新获取取消任务对象
  167.         }
  168.     }
  169.     // 显示窗口句柄
  170.     private void ShowHandle_Click(object sender, EventArgs e)
  171.     {
  172.         label.Text = Handle.ToString("X");
  173.     }
  174.     // 文件内容读取(每次读取 4MB 内容)
  175.     private async Task openFileStream()
  176.     {
  177.         pbar.Value = 0;
  178.         // byte[] content = new byte[4194304];
  179.         byte[] content = new byte[1024];
  180.         int Count = 0;
  181.         using (FileStream fr = new FileStream(selectFileName, FileMode.Open))
  182.         {
  183.             pbar.Maximum = (int)fr.Length; // 文件过大这里会内存溢出
  184.             int total = 0;
  185.             while (true)
  186.             {
  187.                 // 阻塞线程事件
  188.                 // await Task.Run(() => StartPausebutEventsynchro.WaitOne());
  189.                 StartPausebutEventsynchro.WaitOne();
  190.                
  191.                 source.Token.ThrowIfCancellationRequested();
  192.                 // 异步读取 100 字节 文件内容
  193.                 total = await fr.ReadAsync(content, 0, content.Length, source.Token);
  194.                 if (total == 0)
  195.                 {
  196.                     break;
  197.                 }
  198.                 // 进度条
  199.                 Count += total;
  200.                 label.Text = Count.ToString() + " 字节";
  201.                 pbar.Step = total;
  202.                 pbar.PerformStep();
  203.                 Application.DoEvents();
  204.             }
  205.         }
  206.         StartPausebut.Text = "开始";
  207.     }
  208.    
  209.     // 加载文件事件
  210.     private void loadBut_Click(object sender, EventArgs e)
  211.     {
  212.         if (selectFileName == "" || selectFileName == null) return;
  213.         fileList.BeginUpdate();
  214.         fileList.Items.Clear();
  215.         string filePath = Path.GetDirectoryName(selectFileName);
  216.         foreach (var n in Directory.GetFiles(filePath))
  217.         {
  218.             fileList.Items.Add(n);
  219.         }
  220.         fileList.EndUpdate();
  221.     }
  222.     // 文件列表选中条上移
  223.     private void selectUP_Click(object sender, EventArgs e)
  224.     {
  225.         if (fileList.Items.Count == 0) return;
  226.         int count = fileList.Items.Count;
  227.         int current = fileList.SelectedIndex;
  228.         current--;
  229.         if (current < 0)
  230.         {
  231.             current = count - 1;
  232.         }
  233.         fileList.SelectedIndex = current;
  234.         label.Text = fileList.SelectedItem.ToString();
  235.         selectFileName = label.Text;
  236.     }
  237.    
  238.     // 文件列表选中条下移
  239.     private void selectDown_Click(object sender, EventArgs e)
  240.     {
  241.         if (fileList.Items.Count == 0) return;
  242.         int count = fileList.Items.Count;
  243.         int current = fileList.SelectedIndex;
  244.         current++;
  245.         if (current >= count)
  246.         {
  247.             current = 0;
  248.         }
  249.         fileList.SelectedIndex = current;
  250.         label.Text = fileList.SelectedItem.ToString();
  251.         selectFileName = label.Text;
  252.     }
  253. }
复制代码





欢迎光临 批处理之家 (http://bbs.bathome.net/) Powered by Discuz! 7.2