65

You have the asynchronous versions of read and write (begin/end functions), but not of delete (that I can tell). Is there any reason for this? Isn't there as much reason to do delete asynchronously as read/write?

Using threading to simulate asynchronous behavior is not the same as asynchronous functions. Big difference, sure you get the perceived parallel processing, but it's not really preventing blocking, that other thread is still blocked waiting for the file i/o to complete. The real asynchronous functions (begin/end functions) operate at a system level, they queue up file i/o, let the application proceed, and let the application know when it is ready to proceed with the file i/o (allowing you to do other things while you wait for the file i/o to come available).

aepheus
  • 7,827
  • 7
  • 36
  • 51
  • 1
    Maybe there is no need? How long does it take to ask the OS to delete a file anyways? – Chris O May 15 '12 at 18:29
  • 1
    Why do you need to delete asynchronous? You could do it in a background worker. – paparazzo May 15 '12 at 19:15
  • Resources in general, do I really want to block tons of threads waiting for delete? Not a timing thing so much as a thread resource thing. – aepheus May 15 '12 at 20:22
  • 1
    @aepheus Then use a thread pool if you are worried about too many threads. – Branko Dimitrijevic May 15 '12 at 23:29
  • 2
    Could ask the same for copy, move, and many other file operations. My guess is Microsoft picked the two top priorities and those would be my pick also. This a question for Microsoft not SO. – paparazzo May 16 '12 at 16:17
  • 1
    I think a better question is: why isn't there a *synchronous* delete?! In my experience, code executing after File.Delete can still see the file as existing (although it eventually will disappear) – JoelFan Jan 18 '17 at 00:11
  • 3
    @ChrisO A very, very, very long time. Seriously. Always assume that IO is slow. How does the code work on, say, a filesystem that's network mounted over a 128kbps line? – James Moore Mar 01 '17 at 17:36

6 Answers6

47

This would be useful. DeleteFile could take up to 30s if deleting on a disconnected network share.

The reason is likely to be that there is no native function to delete a file asynchronously. The managed APIs generally are wrappers around the unmanaged ones.


Now why is there no native asynchronous file delete API? Native async deletion is hard to implement on Windows as it is. DeleteFile does in pseudocode CreateFile plus NtSetInformationFile(Disposition, Delete) plus CloseHandle. There is no async CreateFile (in my opinion a design bug in Windows). NtSetInformationFile just sets a flag on the file data structure in the kernel. It can't be asynchronous. The actual deletion happens when the last handle is closed. I think this might make CloseHandle blocking which is another design issue in Windows. There is no async CloseHandle.

usr
  • 168,620
  • 35
  • 240
  • 369
  • But the question is: Why isn't there a native function for this? – Legends Oct 10 '19 at 17:04
  • @Legends this question is why does .NET not have it. Native async deletion is hard to implement on Windows as it is. `DeleteFile` does in pseudocode `CreateFile` plus `NtSetInformationFile(Disposition, Delete)` plus `CloseHandle`. There is no async `CreateFile` (in my opinion a design bug in Windows). `NtSetInformationFile` just sets a flag on the file data structure in the kernel. It can't be asynchronous. The actual deletion happens when the last handle is closed. I think this might make `CloseFile` blocking which is another design issue in Windows. There is no async `CloseHandle`. – usr Oct 10 '19 at 17:08
  • Hm,ok. But how can node.js installed on windows delete files in async fashion? Node uses `fs.unlink` to remove files asynchronously, [see here](https://nodejs.org/api/fs.html#fs_fs_unlink_path_callback). Or would this be like using `Task.Run` in C#..? – Legends Oct 10 '19 at 19:38
  • 2
    @Legends yes, that's just a thread pool wrapper. It's fake async. The JavaScript language does not support threading so they have to do something like this. Other libraries do things like that, too. I think libuv makes all file system IO fake async even when true async is supported by the platform. I could be wrong about this. – usr Oct 11 '19 at 07:56
19

The File class doesn't expose an asynchronous file deletion method; however, through the use of the FileStream class, an asynchronous file deletion can still be performed by taking advantage of a specific one of the 13 constructor overloads provided. The following code will delete a file asynchronously:

using (new FileStream(Path, FileMode.Open, FileAccess.Read, FileShare.None, 1, FileOptions.DeleteOnClose | FileOptions.Asynchronous)) ;

I haven't tested it very much, so you may have to modify the usage slightly. (You may want to change FileShare.None to something else if file access by other threads should not be blocked during deletion.) Also, since this code doesn't return any derivation of Task, it would probably be valid to run it with the Task.Run method. Basically, it performs a file deletion which is actually asynchronous on the I/O level, so offloading it onto a thread pool should be okay in this case.

Carsten Führmann
  • 3,119
  • 4
  • 26
  • 24
Alex Fanat
  • 748
  • 10
  • 22
  • 2
    Inside the using block you can await `stream.FlushAsync()` in order to force the deletion and allow the creation of an async method – Phate01 Mar 22 '20 at 17:32
  • I get that the stream itself is async, but is the actual deletion operation? – Moscato Jul 14 '23 at 17:31
15

How about this:

public static class FileExtensions {
   public static Task DeleteAsync(this FileInfo fi) {
      return Task.Factory.StartNew(() => fi.Delete() );
   }
}

Then you can just do:

FileInfo fi = new FileInfo(fileName);
await fi.DeleteAsync(); // C# 5
fi.DeleteAsync().Wait(); // C# 4
Michael Kennedy
  • 3,202
  • 2
  • 25
  • 34
  • 35
    Again just a nice wrapper around threading, not real asynchronous file i/o. – aepheus May 15 '12 at 20:27
  • 2
    @aepheus This is "real" asynchronous I/O, it's just done in userspace instead of the kernel. The difference is that the in-kernel "overlapped" I/O can be cancelled (via `CancelIo`) and _may_ be more efficient. I doubt it would make much difference for a cheap operation such as deleting files, which is probably why it was not exposed in Win32 in the first place. – Branko Dimitrijevic May 15 '12 at 23:28
  • 39
    The main reason to go async is to not block threads (for example in a web-server serving 1000 concurrent requests). This is no help. – usr May 17 '12 at 15:45
  • 2
    @usr: in practice, it's likely that most delete operations are fairly cheap so that the default task scheduler won't spin up 1000 threads even if you use the above code. But *if* you run into threading issues, you could instead use a custom scheduler with few threads (fairly easy), or even just a `TaskCompletionSource<>` with a concurrent queue executing on just one thread (very easy). – Eamon Nerbonne Dec 10 '12 at 12:50
  • MSDN article related avoiding OS thread overuse: [How to: Create a Task Scheduler That Limits Concurrency](http://msdn.microsoft.com/en-us/library/ee789351.aspx) – Eamon Nerbonne Dec 10 '12 at 12:54
  • 2
    @usr: Actually, the main reason to go async is to not block your *control threads* (e.g. those that are responsible for keeping your application responsive). – André Caron Jul 29 '14 at 14:56
  • 2
    @AndréCaron that goes for UI apps (well said for that case). For web apps this is irrelevant. Going async there is for scalability in cases where you have extreme amounts of blocked time (like calling slow services or sleeping). – usr Jul 29 '14 at 14:58
  • @usr Same goes for server apps (it's the only kind of app I write). Just delegate the async file delete operation to a thread pool -- possibly dedicated to file deletion operations -- to limit the number of concurrent threads. – André Caron Jul 29 '14 at 16:46
  • @AndréCaron not sure what you're saying. Delegating blocking work never help with throughput or memory usage on the server. ASP.NET threads are threadpool threads. You don't make room for ASP.NET with that (in case you meant that). Doesn't help in any way. – usr Jul 29 '14 at 17:07
  • 5
    @usr Delegating the file deletion operation to an async task will be async in the sense that the response can be sent to the client even though the file deletion operation hasn't yet completed. This *is* async even if the operation is blocking a thread pool thread. I agree that it would be *better* if this operation was async in the kernel just like a socket or file read is, but it's async in either case. – André Caron Jul 29 '14 at 20:04
  • @AndréCaron if you want to send the response to the client without waiting, no need for async IO. A threadpool thread is fine. This is an orthogonal issue. – usr Jul 29 '14 at 20:05
  • 10
    @usr Your original comment reads "this is no help." It is very helpful, because it implements the most optimal implementation of an asynchronous file delete given the features offered by the kernel. Sure, kernel-space async delete would be even much, much better than that, but it doesn't (yet) exist. – André Caron Jul 29 '14 at 21:16
  • 7
    By that logic you can make *any* operation asynchronous by pushing it to a different thread and that is true. This is not specific to file deletion. There is no need to ask a question about it. In fact the OP has stated he is after true async IO (which *must* be handled in the kernel). – usr Feb 25 '16 at 12:37
  • If you wrap IO-bound work in Task.Run() then you’re just pulling a new thread out to run the code synchronously. It may have a similar signature because it’s returning a Task, but all you’re doing is blocking a different thread. – Rafi Henig Feb 13 '22 at 02:20
9

If nothing else has the file open, opening a FileStream with FileOptions.DeleteOnClose will cause Windows delete the file when the stream is closed. This may help you if you're already opening a FileStream to do async reading/writing, though if you need to wait for the deletion to finish it doesn't help you (although according to @JoelFan waiting for File.Delete to finish doesn't guarantee the file is actually deleted anyway).

Interestingly enough, in testing against a network share, it seems that opening the stream as such and doing nothing with it is significantly faster (~40%) than File.Delete:

using (new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.None, 4096, FileOptions.DeleteOnClose)) { }
ejohnson
  • 655
  • 7
  • 18
0

I may be wrong, but in the case someone tries to access the same file on a cross thread operation, it would be needed to block the file for access until the delete operation is completed.

Rodrigo Vedovato
  • 1,008
  • 6
  • 11
  • Wouldn't file locking still occur regardless of asynchronous? Async file i/o basically just allows you to not block while the os gets the file resources ready for you, then lets you know when it's ready. – aepheus May 15 '12 at 20:26
-5

Perhaps because you can just as easily do it yourself?

var t = Task.Factory.StartNew(() => File.Delete("file.txt"));
// ...
t.Wait();
Branko Dimitrijevic
  • 50,809
  • 10
  • 93
  • 167
  • LOL, we answered at the exact same time. Now they have two ways. – Michael Kennedy May 15 '12 at 19:41
  • 14
    This would basically create a new thread and run a synchronous delete. That is not what I'm looking for. The real asynchronous functions aren't using threading but rather make use of native functions. If you use a thread you're still blocking that thread to wait for the file i/o, if you use async functions your not. – aepheus May 15 '12 at 20:19
  • 1
    @aepheus What you are describing is "overlapped" I/O. I'm not sure why there is no [DeleteFile](http://msdn.microsoft.com/en-us/library/aa363915(v=vs.85)) variant that accepts `OVERLAPPED` structure, but .NET wraps these functions and consequently doesn't provide what you asked. BTW, the code above will not necessarily create a new thread - it will use the thread pool and won't "bombard" the OS with too many threads. Did you actually measure and found that the task-based approach would be a performance problem? – Branko Dimitrijevic May 15 '12 at 23:00
  • 1
    Offloading work to another thread is not the same thing as asynchronous. The whole point of asynchronous is that no work and no thread is blocked while that operation is completing. – Austin Salgat Apr 20 '17 at 20:39
  • This will free up your UI if you await it, but it isn't true async, – rollsch Feb 21 '18 at 23:59