C# 异步读取文件任务,一次取消不了任务,需要多次才能取消任务

Cool_Breeze2021-5-665

解决了。异步执行时,主线程会收到终止异常。所以需要在主线程中终止任务后,在开始新的任务![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)
  • wwh10042021-5-6
    引用2
    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;    }}
  • wwh10042021-5-6
    引用3

    说实话,代码问题挺多的,全修改完挺麻烦的,目前就把看见的逻辑错误改正确了。

    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;    }}
  • wwh10042021-5-6
    引用4
    那个targetEnd相关的,没太看懂是干嘛的....如果任务已经完成了,那不需要手动取消的,可以不需要传那个cancellationtoken,也不需要targetEnd再补充个下,那个分块读取的缓冲区设置的太小了,vs调试器看着clr在疯狂进行gc,按道理给个几mb都没问题。如果只是要文件完整内容,一次性全部读出来也可以,.net内部已经设计好缓冲区了,不需要自己再弄个。
  • 楼主Cool_Breeze2021-5-6
    引用5
    wwh1004 发表于 2021-5-6 20:02
    [md]说实话,代码问题挺多的,全修改完挺麻烦的,目前就把看见的逻辑错误改正确了。``` cs

    感谢大佬指点,但是问题还是存在,打开大文件,中途还是无法取消!
  • wwh10042021-5-6
    引用6
    Cool_Breeze 发表于 2021-5-6 20:08
    感谢大佬指点,但是问题还是存在,打开大文件,中途还是无法取消!

    取消就是从头开始读取了,你是要暂停还是取消?
  • 楼主Cool_Breeze2021-5-6
    引用7
    wwh1004 发表于 2021-5-6 20:10
    取消就是从头开始读取了,你是要暂停还是取消?

    就是打开大文件后,还在读取中,又重新选择一个小文件打开,小文件跑完,大文件还在跑。逻辑是:打开小文件时,读取大文件任务就该是取消了!
  • 楼主Cool_Breeze2021-5-6
    引用8
    wwh1004 发表于 2021-5-6 20:06
    那个targetEnd相关的,没太看懂是干嘛的....如果任务已经完成了,那不需要手动取消的,可以不需要传那个can ...

    看到 有个 ReadAsync 重载是没有 token的。targetEnd其实就是检测读取文件任务是否完成!
  • 楼主Cool_Breeze2021-5-6
    引用9
    wwh1004 发表于 2021-5-6 20:06
    那个targetEnd相关的,没太看懂是干嘛的....如果任务已经完成了,那不需要手动取消的,可以不需要传那个can ...

    感谢指正! 我就说读取个文件占用cpu那么多资源!
  • 楼主Cool_Breeze2021-5-6
    引用10
    wwh1004 发表于 2021-5-6 20:41
    [md]``` cs
    using System;
    using System.Drawing;

    成功了。大佬能不能教教 () => stopped 这个委托它做了啥?
  • 2021-5-9
    引用11
  • 游客
    12
返回