【问题标题】:Delete files asynchronously in C#在 C# 中异步删除文件
【发布时间】:2021-08-17 08:08:03
【问题描述】:

我有一个场景,我需要将文件从本地磁盘一个一个上传到 azure blob 存储,并在上传后在磁盘上删除它们。问题是,一旦上传了文件,我不想等到该文件被删除后再上传下一个文件。

我可以看到.NET 中没有异步文件删除。那么处理这种情况的最佳方法是什么,我该如何实现呢.. 目前我正在使用以下代码,但它似乎不稳定。

private event EventHandler FileDeleteEvent;
public async Task SendBulkTelemetryMessageConsumer()
{
  try
  {
    this.FileDeleteEvent +=this.FileDeleteEventHandler;
    // Logic to upload a file to blob storage
    await this.Log.Debug($"Deleting the file {file}");
    this.FileDeleteEvent(file);
  }
  catch()
  {
    // Exception handling
  }
}
private void FileDeleteEventHandler(string filePath)
{
        if (!File.Exists(filePath))
        {
            this.Log.Debug($"The file {filePath} doesn't exist.");
        }
        else
        {
            while (this.IsFileLocked(filePath))
            {
                Thread.Sleep(1000);
            }

            this.Log.Debug($"Deleting the file from the path {filePath}");
            File.Delete(filePath);
        }
}

private bool IsFileLocked(string filePath)
{
        try
        {
            using (File.Open(filePath, FileMode.Open))
            {
                return true;
            }
        }
        catch (IOException e)
        {
            this.Log.Error("Exception occured while deleting the file, Exception is {e}", e);
        }

        return false;
}

我应该让事件处理程序异步无效还是异步任务?

或者在我不必使用任何事件和事件处理程序的情况下使用 Fire and Forget 方法是否更合适?

【问题讨论】:

  • 谁打电话给SendBulkTelemetryMessageConsumerfile 来自哪里?你能提供一个更完整的例子吗?
  • 也不要Thread.Sleep,使用Task.Delay并等待它
  • 也许这会有所帮助; stackoverflow.com/questions/10606328/…
  • @asaf92,SendBulkTelemetryMessageConsumer 方法由其他内部方法之一调用,该文件来自从配置文件中读取文件路径。无论如何,我已经在这里注释掉了该逻辑,因为该代码块(获取文件,根据我们的业务逻辑验证它们并上传它们)非常大并且与我提出的问题无关。
  • 什么时候删除文件需要这么长时间?就像写分配表一样。

标签: c# events async-await event-handling file-handling


【解决方案1】:

你能做的最好的是将文件的删除包装在一个任务中,然后等待它,或者只是触发并忘记(这取决于你想要什么,但一定要注意在不等待时丢失异常等后果任务):

var deletionTask = Task.Run(() => File.Delete(path));

【讨论】:

  • 如果你在 Task.Run() 中包装 IO-bound 工作,那么你只是拉出一个新线程来同步运行代码。它可能具有相似的签名,因为它正在返回一个任务,但你所做的只是阻塞了一个不同的线程。
【解决方案2】:

我的解决方案是有两个并行进程:

进程 2 从磁盘中删除文件

进程 1 上传文件,然后将它们添加到进程 2 的列表中

为这两个进程找到一个合适的(线程安全的)集合是一个小问题。我会说ConcurrentQueue[T] 应该这样做。但如果你愿意,你可以像 Channel[T] 那样复杂/异国情调。

请注意,这样做实际节省的时间应该是最少的。除非您安全地擦除文件,否则“删除”文件只涉及删除 FS 表条目。影响非常低的操作,不应对上传文件的繁重负载。

在处理各种多任务时必须真正注意的一点是不要吞下异常。通常你需要编写糟糕的代码来吞下异常——比如全部捕获或catch (Exception)。使用 Multtiasking,您可以意外地做到这一点。我有 two articles 对正确的异常处理以及为什么会不好。

【讨论】:

    【解决方案3】:

    使用自旋锁(延迟等待资源释放的循环)表明了设计 错误。我也认为与上传相比,删除本地文件是一个非常快速的操作。 通用上传类可能如下所示:

    public class AzureUploader
    {
        public static async Task<AzureUploader> Connect()
        {
            var uploader = new AzureUploader();
            // Initialize your client with your credentials. Return initialized object.
            return uploader;
        }
    
        public Task UploadAndDelete(string filename)
        {
            return UploadToAzure(filename)
                .ContinueWith(task =>
                    {
                        if (task.Status == TaskStatus.RanToCompletion)
                        {
                            Console.WriteLine("Upload was successful, now we can delete the file.");
                            File.Delete(filename);
                        }
                        else if (task.Status == TaskStatus.Faulted)
                        {
                            Console.WriteLine("An error occurred while uploading to Azure.");
                            Console.WriteLine(task.Exception.GetBaseException().Message);
                        }
                    });
        }
    
        private async Task UploadToAzure(string filename)
        {
            // Closes the stream at the end of the method so that the file can be deleted.
            using var stream = File.OpenRead(filename);
            // Upload file to azure
        }
    }
    

    用法:

    var uploader = await AzureUploader.Connect();
    await uploader.UploadAndDelete("myfile.ext");
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-08-05
      • 1970-01-01
      • 2012-05-23
      • 2022-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多