How to implement an async File.Delete/Create/Move?

17,164

If you must do this, I would write the methods like this (note: I readily agree that this is exactly what Stephens Cleary and Toub are urging us not to do):

public static Task DeleteAsync(string path)
{
     Guard.FileExists(path);

     return Task.Run(() => { File.Delete(path); });
}

public static Task<FileStream> CreateAsync(string path)
{
     Guard.IsNotNullOrWhitespace(path);

     return Task.Run(() => File.Create(path));
}

public static Task MoveAsync(string sourceFileName, string destFileName)
{
     Guard.FileExists(sourceFileName);
     Guard.IsNotNullOrWhitespace(destFileName);

     return Task.Run(() => { File.Move(sourceFileName, destFileName); });
}

This cleans up the code a bit and eliminates excessive context/thread-switching.

In the context of a GUI-based program, it seems fine to use wrappers like these. I think as long as you don't create a whole new library with synchronous and asynchronous APIs in parallel, as described in the articles referred to, this isn't terrible.

But for me, the bigger problem is that none of these operations are likely to take long enough to justify making them asynchronous in the first place. I.e. the usual reason you run things in a Task from a UI thread is because your UI thread can't afford to wait around while the operation completes. But here, for each of these operations, the act of sending the operation to the thread pool, and then picking up with the continuation after it's done, are likely to add as much performance overhead to your program as the operation itself.

It's for that reason that I would recommend against bothering with an asynchronous version of the methods at all. Just call the Create(), Delete(), and Move() methods from the UI directly.

(Note: one exception to the above is if dealing with a network share or different volumes, where a Move() involves actually copying data. So even there, it's a big huge "it depends". Similarly, while Delete() and Create() would normally be fast even over a network, they could take awhile if the operation actually is going to fail. You may actually have a good use case for running the operations asynchronously there).

Share:
17,164
Fabe
Author by

Fabe

Working in software development since 2006 and specialised in solution architecture based on the Microsoft .NET platform. I aim to design better, faster and cheaper solutions based on platforms and to lead development teams to strive for customer satisfaction.

Updated on June 05, 2022

Comments

  • Fabe
    Fabe almost 2 years

    Since I have to do a lot of file I/O operations in my application, I decided to implement them asynchronously. Looking into the MSDN, there are no asynchronous counterparts for File.Create, File.Delete and File.Move. As I learned, the reason is the nonexistence of an asynchronous Win32 implementation for file delete, create or move, So I ended up with the following solution:

    public static Task DeleteAsync(string path)
    {
         Guard.FileExists(path);
    
         return Task.Run(() => File.Delete(path));
    }
    
    public static Task<FileStream> CreateAsync(string path)
    {
         Guard.IsNotNullOrWhitespace(path);
    
         return Task.Run(() => File.Create(path));
    }
    
    public static Task MoveAsync(string sourceFileName, string destFileName)
    {
         Guard.FileExists(sourceFileName);
         Guard.IsNotNullOrWhitespace(destFileName);
    
         return Task.Run(() => { File.Move(sourceFileName, destFileName); });
    }
    

    Considering the paradigma "Don’t use Task.Run in Libraries" , I am wondering if there is a better implementation or should I fallback to synchronous code?

    Many thanks in advance!

    Edits:


    • Improved the code based on Peter Duniho recommendation
    • Added the link to the original blog post provided by Sriram Sakthivel