【问题标题】:How to delete a file which is used in another thread or process in c#如何在c#中删除在另一个线程或进程中使用的文件
【发布时间】:2018-01-15 13:13:50
【问题描述】:

在这里,我有一个包含 2 个文件夹和该文件夹中的一些 xml 文件的格式文件。打开该文件时,我将该文件提取到临时位置,如 appdata。

然后读取每个文件并根据保存的文件文本呈现一些 UI 元素。打开时,我将显示等待指示框,并且加载的进程正在后台与调度程序一起执行。

如果我想中止该操作,请单击中止并且不需要执行任何操作(渲染 UI 元素)。在这里我将删除该临时位置,它将显示“该进程无法访问此文件,因为它被另一个进程使用”异常。我可以知道如何删除该文件或该文件使用哪个进程吗?

这是我的代码:

我进行了编辑,使用 CancellationToken 中止所有方法。

var backGroundWorker = new CancelSupportedBackgroundWorker { WorkerSupportsCancellation = true };
CancellationTokenSource source = new CancellationTokenSource(); 
AlertBox = new AlertBox { IsBusy = true };
AlertBox.WaitingText = Loading;
AlertBox.WaitingHeaderText = Loading Indicator;
AlertBox.AbortButton.Click += (obj, arg) =>
{
    App.Current.Dispatcher.Invoke(new Action(() =>
    {
        string tempDir = C:\Users\Lenovo\AppData + FileAndDirectoryConstants.TempDirFolder;
        if (Directory.Exists(tempDir))
        {
            Directory.Delete(tempDir, true);
        }
      }));

GC.Collect();
source.Cancel();
GC.WaitForPendingFinalizers();
backGroundWorker.CancelAsync();
backGroundWorker.Abort();
backGroundWorker.Dispose();
}

backGroundWorker.DoWork += (obj, arg) =>
{
    try
    {
        RenderUiElements(fileName,(CancellationToken)arg.Argument);
    }
    catch (ThreadAbortException)
    {
        Dispatcher.Invoke(() =>
        {
            AlertBox.IsBusy = false;
        }, System.Windows.Threading.DispatcherPriority.Background);
        arg.Cancel = true;
    }
};
backGroundWorker.RunWorkerCompleted += (obj, arg) =>
{
    AlertBox.isBusy = false;
}
backGroundWorker.RunWorkerAsync(source.Token);

private void RenderUiElements(string fileName,CancellationToken token)
{
    try
    {
        if(token != default(CancellationToken))
           if(token.isCancellationRequested)
              return;
        App.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(
        delegate ()
        {
            using (fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.None))
            {                                
                LoadReport(fileStream, fileName,token);
            }
        }));
    }
    catch (ThreadAbortException)
    {
        return;
    }
    finally
    {
        if (fileStream != null)
        {
            fileStream.Close();
            fileStream.Dispose();
        }
    }
}

【问题讨论】:

  • 我认为,LoadReport 在您中止操作时仍在使用fileStream,这就是您收到消息的原因
  • 是的,就是这个原因。因为 Loadreport 正在使用该文件流进行一些操作。那时我们需要中止该操作并尝试删除该文件夹。
  • 该方法用于检查文件是否被锁定。但我需要删除那个文件。
  • 为什么不直接取消LoadReport中的操作呢?在此之后,您应该可以删除该文件

标签: c# multithreading backgroundworker delete-file ioexception


【解决方案1】:

只有两种方法可以删除另一个进程正在使用的文件

  • 强制关闭文件上当前打开的所有文件句柄,然后删除该文件
  • P/调用 Windows MoveFileEx 函数,并使用带有 NULL 目标名称的 MOVEFILE_DELAY_UNTIL_REBOOT 标志。这将在您重新启动时删除该文件。

我建议您执行后者,因为执行前者很麻烦,并且可能会导致其他正在运行的应用出现严重问题。有关后者的更多信息,请参阅http://www.pinvoke.net/default.aspx/kernel32.movefileex

【讨论】:

  • 如何关闭当前在一个文件上打开的所有文件句柄
  • 我故意没有为此举个例子,因为这样做很糟糕。如果你想这样做,你需要做一些谷歌搜索。确保您确实想要这样做,并且不是您自己的代码仍然具有特定文件的打开句柄。请考虑采用后一种方法
【解决方案2】:

终于找到了解决办法,

这里的 Filestream 对象没有正确处理,只有在 LoadReport 方法完全之后才被处理。如果我在执行 LoadReport 时单击中止,则不会释放文件流。因此发生了错误。

所以在 LoadReport() 方法中清除 Filestream 对象。

private void LoadReport(stream filestream,CancellationToken token)
{
 filestream.Close();
 filestream.Dispose();
}

【讨论】:

    猜你喜欢
    • 2019-06-26
    • 2011-08-09
    • 1970-01-01
    • 2012-10-27
    相关资源
    最近更新 更多