async void方法中await Task.Run无效?waveOut播放后无法删文件求助
问题分析与解决方案
我明白你遇到的问题了——想用await Task.Run等WaveOut播放完再删文件,但结果程序根本没等播放结束就去执行删除操作,还碰到文件占用的报错。这问题其实出在你对waveOut.Play()的工作方式理解上,咱们一步步来解决:
为什么你的await Task.Run无效?
waveOut.Play()本身就是非阻塞的异步启动方法——调用它之后,它只是启动播放流程就立刻返回了,并不会等待整个音频播放完毕。所以await Task.Run(() => waveOut.Play())其实只是等待Play()方法调用完成,而不是等待播放全程结束。这就导致你刚启动播放就去删文件,自然会触发文件占用的问题。
正确的解决思路
我们需要监听WaveOut的播放结束事件,或者把播放过程封装成可等待的异步任务,确保删除操作在播放完全结束后执行。
方法一:利用PlaybackStopped事件(最常用)
WaveOut类自带PlaybackStopped事件,播放完成(或者被停止/中断)时会触发这个事件,我们可以在事件回调里安全地处理文件删除:
public void PlayAudio(object sender, GenericEventArgs<Stream> args) { var waveOut = new WaveOut(); var audioStream = args.EventArg; // 假设这是你的音频流 waveOut.Init(audioStream); // 订阅播放停止事件 waveOut.PlaybackStopped += (senderObj, eventArgs) => { // 必须先释放资源,否则文件会一直被占用 waveOut.Dispose(); audioStream.Dispose(); // 现在可以安全删除文件了 File.Delete("你的目标文件路径"); }; waveOut.Play(); }
方法二:封装成可await的异步任务
如果你更习惯用async/await的写法,可以用TaskCompletionSource把播放过程包装成可等待的Task:
public async void PlayAudio(object sender, GenericEventArgs<Stream> args) { var waveOut = new WaveOut(); var audioStream = args.EventArg; waveOut.Init(audioStream); // 创建一个TaskCompletionSource来监听播放结束 var playbackCompletion = new TaskCompletionSource<bool>(); waveOut.PlaybackStopped += (senderObj, eventArgs) => { playbackCompletion.TrySetResult(true); // 释放资源是关键 waveOut.Dispose(); audioStream.Dispose(); }; waveOut.Play(); // 等待播放完全结束 await playbackCompletion.Task; // 现在执行删除操作 File.Delete("你的目标文件路径"); }
几个关键注意点
- 必须释放资源:不管用哪种方法,都要确保
waveOut和音频流被正确Dispose,否则文件句柄会一直被占用,就算播放结束也删不了文件。 - 避免错误的线程切换:不要用
Task.Run包裹waveOut.Play(),完全没必要,还会造成不必要的线程开销。 - 流的打开方式:如果你的音频流是从文件直接打开的,确保用只读共享模式(比如
File.OpenRead()),不要用独占模式打开,否则播放时文件本身就会被锁死。
内容的提问来源于stack exchange,提问作者Rodnik
相关产品推荐
相关产品推荐

