roim
roim

Reputation: 4930

OpenRead asynchronously

I'm using the following C# code to read a tiny text file over a network share:

string fileContent;
using (var stream = File.OpenRead(filePath))
using (var reader = new StreamReader(stream, FileEncoding))
{
    fileContent = await reader.ReadToEndAsync();
}

Even though the text file is very small (less than 10 KB) this operation sometimes takes ~7 seconds to run. When that happens, I've noticed most of the time is spent on

File.OpenRead(filePath)

This is probably due to Windows having to resolve the file share and to acquire locks on the file over the network. As that method call is not asynchronous, this is blocking my current thread for several seconds.

Is there a safe way to read a file from disk asynchronously that also performs OpenRead asynchronously?

Upvotes: 12

Views: 5660

Answers (3)

HackSlash
HackSlash

Reputation: 5811

Much has changed in the last 8 years. The syntax to do what is asked in this question is as follows:

await using var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 16384, FileOptions.Asynchronous);
using var reader = new StreamReader(stream);
string fileContent = await reader.ReadToEndAsync();

Doing this over a network may or may not be supported depending upon many factors but if you write your code this way then it could be async if Microsoft allows async access to the destination. Either way, it will work, even if the underlying SMB connection doesn't have an async API. It is no worse than what you were doing before IMO.

Upvotes: 0

async Task<Stream> OpenReadAsync()
{      
    FileStream? s = null;

    await Task.Run(() => {
        s = File.OpenRead(FileName);});

    if (s == null) throw new Exception("Error opening file {FileName}");

    return s;
}

Upvotes: -1

Stephen Cleary
Stephen Cleary

Reputation: 457292

No, unfortunately this is missing in the Win32 API. Device drivers do have the notion of an "asynchronous open", so the infrastructure is there; but the Win32 API does not expose this functionality.

Naturally, this means that .NET can't expose that functionality, either. You can, however, use a "fake asynchronous" operation - i.e., wrap your file read within a Task.Run, so that your UI thread isn't blocked. However, if you're on ASP.NET, then don't use Task.Run; just keep the (blocking) file open as it is.

Upvotes: 18

Related Questions