解决了。异步执行时,主线程会收到终止异常。所以需要在主线程中终止任务后,在开始新的任务![C#] 纯文本查看 复制代码
using System;using System.Drawing;using System.Threading;using System.IO;using System.Threading.Tasks;using System.Windows.Forms;public class Form1 : Form{ [STAThread] public static void Main() { Application.EnableVisualStyles(); Application.Run(new Form1()); } private readonly ProgressBar pbar; private readonly Label label; private readonly Button StartPausebut; private readonly Button openFileBut; private readonly Button Stopbut; private static CancellationTokenSource source = new CancellationTokenSource(); private readonly EventWaitHandle StartPausebutEventsynchro = new EventWaitHandle(false, EventResetMode.ManualReset); private string selectFileName; // 窗体 public Form1() { // 进度条 pbar = new ProgressBar(); pbar.Width = 500; pbar.Location = new Point(10, 20); pbar.Visible = true; // 开始,暂停按键 StartPausebut = new Button(); StartPausebut.Text = "开始"; StartPausebut.Location = new Point(100, 60); StartPausebut.Click += new EventHandler(StartPausebut_Click); // 取消按键 Stopbut = new Button(); Stopbut.Text = "终止读取"; Stopbut.Location = new Point(190, 60); Stopbut.Click += new EventHandler(Stopbut_Click); // 选择文件状态 openFileBut = new Button(); openFileBut.Text = "选择文件"; openFileBut.Location = new Point(10, 60); openFileBut.Click += new EventHandler(openFileBut_Click); // 提示信息标签 label = new Label(); label.Location = new Point(10, 90); label.AutoSize = true; this.Controls.Add(StartPausebut); this.Controls.Add(pbar); this.Controls.Add(label); this.Controls.Add(Stopbut); this.Controls.Add(openFileBut); this.Width = 600; } // 开始,暂停 按键事件 private async void StartPausebut_Click(object sender, EventArgs e) { if (StartPausebut.Text == "开始") { StartPausebut.Text = "暂停"; await Task.Run(() => StartPausebutEventsynchro.Set()); // 任务非阻塞状态 } else if (StartPausebut.Text == "暂停") { StartPausebut.Text = "开始"; await Task.Run(() => StartPausebutEventsynchro.Reset()); // 任务阻塞状态 } } // 选择文件 private async void openFileBut_Click(object sender, EventArgs e) { // 选择文件对话框 OpenFileDialog dlg = new OpenFileDialog(); dlg.Filter = "Text documents (*.*)|*.*"; dlg.ShowDialog(); selectFileName = dlg.FileName; label.Text = selectFileName; if (selectFileName == "") { return; } // 每次选择文件都会取消之前的任务! // 取消任务 await openFileStream(); // 捕获取消任务后引发的异常 } private void Stopbut_Click(object sender, EventArgs e) { source.Cancel(); // 取消任务 } // 文件内容读取(每次读取 100 字节 内容) private async Task openFileStream() { pbar.Value = 0; byte[] content = new byte[10240]; int Count = 0; using (FileStream fr = new FileStream(selectFileName, FileMode.Open)) { pbar.Maximum = (int)fr.Length; // 文件过大这里会内存溢出 int total = 0; while (true) { // 阻塞线程事件 await Task.Run(() => StartPausebutEventsynchro.WaitOne()); // 异步读取 100 字节 文件内容 try { total = await fr.ReadAsync(content, 0, content.Length, source.Token); } catch (Exception err) { label.Text = err.Message; source.Dispose(); // 释放资源 source = new CancellationTokenSource(); //重新获取取消任务对象 break; } if (total == 0) { break; } // 进度条 Count += total; label.Text = Count.ToString() + " 字节"; pbar.Step = total; pbar.PerformStep(); Application.DoEvents(); } } }}

最新回复 (10)
using System;using System.Drawing;using System.Threading;using System.IO;using System.Threading.Tasks;using System.Windows.Forms;public class Form1 : Form { [STAThread] public static void Main() { Application.EnableVisualStyles(); Application.Run(new Form1()); } private ProgressBar pbar; private Label label; private Button StartPausebut; private Button openFileBut; private static CancellationTokenSource source = new CancellationTokenSource(); private bool paused; private bool stopped; private System.Threading.SemaphoreSlim StartPausebutEventsynchro = new SemaphoreSlim(0); private string selectFileName; private bool targetEnd = false; // 窗体 public Form1() { // 进度条 pbar = new ProgressBar(); pbar.Width = 500; pbar.Location = new Point(10, 20); pbar.Visible = true; // 开始,暂停按键 StartPausebut = new Button(); StartPausebut.Text = "开始"; StartPausebut.Location = new Point(100, 60); StartPausebut.Click += new EventHandler(StartPausebut_Click); // 选择文件状态 openFileBut = new Button(); openFileBut.Text = "选择文件"; openFileBut.Location = new Point(10, 60); openFileBut.Click += new EventHandler(openFileBut_Click); // 提示信息标签 label = new Label(); label.Location = new Point(10, 90); label.AutoSize = true; this.Controls.Add(StartPausebut); this.Controls.Add(pbar); this.Controls.Add(label); this.Controls.Add(openFileBut); this.Width = 600; } // 开始,暂停 按键事件 private void StartPausebut_Click(object sender, EventArgs e) { if (StartPausebut.Text == "开始") { StartPausebut.Text = "暂停"; paused = true; // 任务非阻塞状态 } else if (StartPausebut.Text == "暂停") { StartPausebut.Text = "开始"; paused = false; StartPausebutEventsynchro.Release(); // 任务阻塞状态 } } // 选择文件 private async void openFileBut_Click(object sender, EventArgs e) { // 选择文件对话框 OpenFileDialog dlg = new OpenFileDialog(); dlg.Filter = "Text documents (*.*)|*.*"; dlg.ShowDialog(); selectFileName = dlg.FileName; label.Text = selectFileName; if (selectFileName == "") { return; } try { // 每次选择文件都会取消之前的任务! // 取消任务 if (targetEnd) { source.Cancel(); // 取消任务 await Task.Run(() => SpinWait.SpinUntil(() => stopped)); targetEnd = false; } await openFileStream(); // 捕获取消任务后引发的异常 } catch (Exception err) { label.Text = err.Message; } finally { source.Dispose(); // 释放资源 source = new CancellationTokenSource(); //重新获取取消任务对象 stopped = true; } } // 文件内容读取(每次读取 100 字节 内容) private async Task openFileStream() { targetEnd = true; // 标记读取文件状态(正在读取,完成读取) pbar.Value = 0; byte[] content = new byte[10240]; int Count = 0; using (FileStream fr = new FileStream(selectFileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { pbar.Maximum = (int)fr.Length; int total = 0; while (true) { // 阻塞线程事件 if (paused) await StartPausebutEventsynchro.WaitAsync(source.Token); // 异步读取 100 字节 文件内容 total = await fr.ReadAsync(content, 0, content.Length, source.Token); if (total == 0) { break; } // 进度条 Count += total; label.Text = Count.ToString() + " 字节"; pbar.Step = total; pbar.PerformStep(); } } targetEnd = false; }}
说实话,代码问题挺多的,全修改完挺麻烦的,目前就把看见的逻辑错误改正确了。
using System;using System.Drawing;using System.Threading;using System.IO;using System.Threading.Tasks;using System.Windows.Forms;public class Form1 : Form { [STAThread] public static void Main() { Application.EnableVisualStyles(); Application.Run(new Form1()); } private ProgressBar pbar; private Label label; private Button StartPausebut; private Button openFileBut; private static CancellationTokenSource source = new CancellationTokenSource(); private bool paused; private System.Threading.SemaphoreSlim StartPausebutEventsynchro = new SemaphoreSlim(0); private string selectFileName; private bool targetEnd = false; // 窗体 public Form1() { // 进度条 pbar = new ProgressBar(); pbar.Width = 500; pbar.Location = new Point(10, 20); pbar.Visible = true; // 开始,暂停按键 StartPausebut = new Button(); StartPausebut.Text = "开始"; StartPausebut.Location = new Point(100, 60); StartPausebut.Click += new EventHandler(StartPausebut_Click); // 选择文件状态 openFileBut = new Button(); openFileBut.Text = "选择文件"; openFileBut.Location = new Point(10, 60); openFileBut.Click += new EventHandler(openFileBut_Click); // 提示信息标签 label = new Label(); label.Location = new Point(10, 90); label.AutoSize = true; this.Controls.Add(StartPausebut); this.Controls.Add(pbar); this.Controls.Add(label); this.Controls.Add(openFileBut); this.Width = 600; } // 开始,暂停 按键事件 private void StartPausebut_Click(object sender, EventArgs e) { if (StartPausebut.Text == "开始") { StartPausebut.Text = "暂停"; paused = true; // 任务非阻塞状态 } else if (StartPausebut.Text == "暂停") { StartPausebut.Text = "开始"; paused = false; StartPausebutEventsynchro.Release(); // 任务阻塞状态 } } // 选择文件 private async void openFileBut_Click(object sender, EventArgs e) { // 选择文件对话框 OpenFileDialog dlg = new OpenFileDialog(); dlg.Filter = "Text documents (*.*)|*.*"; dlg.ShowDialog(); selectFileName = dlg.FileName; label.Text = selectFileName; if (selectFileName == "") { return; } try { // 每次选择文件都会取消之前的任务! // 取消任务 if (targetEnd) { source.Cancel(); // 取消任务 targetEnd = false; } await openFileStream(); // 捕获取消任务后引发的异常 } catch (Exception err) { label.Text = err.Message; } finally { source.Dispose(); // 释放资源 source = new CancellationTokenSource(); //重新获取取消任务对象 } } // 文件内容读取(每次读取 100 字节 内容) private async Task openFileStream() { targetEnd = true; // 标记读取文件状态(正在读取,完成读取) pbar.Value = 0; byte[] content = new byte[100]; int Count = 0; using (FileStream fr = new FileStream(selectFileName, FileMode.Open)) { pbar.Maximum = (int)fr.Length; int total = 0; while (true) { // 阻塞线程事件 if (paused) await StartPausebutEventsynchro.WaitAsync(); // 异步读取 100 字节 文件内容 total = await fr.ReadAsync(content, 0, content.Length, source.Token); if (total == 0) { break; } // 进度条 Count += total; label.Text = Count.ToString() + " 字节"; pbar.Step = total; pbar.PerformStep(); Application.DoEvents(); } } targetEnd = false; }}
- 引用5楼
wwh1004 发表于 2021-5-6 20:02
[md]说实话,代码问题挺多的,全修改完挺麻烦的,目前就把看见的逻辑错误改正确了。``` cs
感谢大佬指点,但是问题还是存在,打开大文件,中途还是无法取消! - 引用7楼
wwh1004 发表于 2021-5-6 20:10
取消就是从头开始读取了,你是要暂停还是取消?
就是打开大文件后,还在读取中,又重新选择一个小文件打开,小文件跑完,大文件还在跑。逻辑是:打开小文件时,读取大文件任务就该是取消了! - 引用8楼
wwh1004 发表于 2021-5-6 20:06
那个targetEnd相关的,没太看懂是干嘛的....如果任务已经完成了,那不需要手动取消的,可以不需要传那个can ...
看到 有个 ReadAsync 重载是没有 token的。targetEnd其实就是检测读取文件任务是否完成! - 引用9楼
wwh1004 发表于 2021-5-6 20:06
那个targetEnd相关的,没太看懂是干嘛的....如果任务已经完成了,那不需要手动取消的,可以不需要传那个can ...
感谢指正! 我就说读取个文件占用cpu那么多资源! - 引用10楼
wwh1004 发表于 2021-5-6 20:41
[md]``` cs
using System;
using System.Drawing;
成功了。大佬能不能教教 () => stopped 这个委托它做了啥? - 引用11楼
- 游客12楼
发新帖
主题数 460490 | 帖子数 7987403 | 注册排名 2 |
精彩推荐
- V2EXChrome 的扩展开发...我一定要吐槽 Manifest V3
- 全球主机交流大佬们 有没有完整的数字货币交易所源码 最好是php的 带ap...
- 耳机大家坛分享收集的欧洲音乐会蓝光碟资源
- V2EXGoogle adsense/play/admob 回款结汇(支持大陆,香港,新加坡谷歌用户)无结汇额度限制
- V2EX现在汽车油价这么贵,有什么替换方案?
- V2EX求教一个 sql 优化问题
- 全球主机交流和记 国际万能卡充值问题[已解决]
- 全球主机交流我在想一个问题
- chiphell5900x+6650xt sf600 or sf750
- V2EX微信支付出 bug 了?刚刚小程序点外卖,微信支付一直在 loading
- 全球主机交流微软这是被薅疼了吗?Mover.io 停用时间线
- chiphell请问下,现阶段tp6088和tp5048买哪个好?