- 
                Notifications
    You must be signed in to change notification settings 
- Fork 5.2k
Description
Background and Motivation
When using System.IO.File and/or System.IO.FileInfo for opening, creating and writing files you do not have the option to properly open FileStreams for use with async methods.
A very common mistake/issue that occurs because of it is that files are opened through methods like File.OpenWrite or new FileInfo(x).Open() and the FileStream is then used with async/await operations like WriteAsync or ReadAsync. However when this is done you will incur a performance hit as the stream is not configured to be used in this way.
The proper way to use FileStreams with async await is to open a FileStream through the constructor with and supplying the argument isAsync with true. However System.IO.File and System.IO.FileInfo expose a lot of convenient shorthands but lack the possibility to open the streams properly for async actions. leading also to the misconception that async await with file IO is actually not good.
Proposed API
@adamsitnik proposed the use of a FileOptions and supply additional overloads to System.IO.StreamReader, System.IO.StreamWriter , System.IO.File and System.IO.FileInfo so not only Files can be opened with FileOptions.Asynchronous but also with FileOptions.SequentialScan.
Comment: #24698 (comment)
public static partial class File
{
    public StreamWriter AppendText(string path)
+   public StreamWriter AppendText(string path, FileOptions options)
    public static System.IO.FileStream Create(string path)
+   public static System.IO.FileStream Create(string path, System.IO.FileOptions options)
    public static System.IO.FileStream Create(string path, int bufferSize)
    public static System.IO.FileStream Create(string path, int bufferSize, System.IO.FileOptions options)
    public static System.IO.StreamWriter CreateText(string path)
+   public static System.IO.StreamWriter CreateText(string path, System.IO.FileOptions options)   
    public static System.IO.FileStream Open(string path, System.IO.FileMode mode)
+   public static System.IO.FileStream Open(string path, System.IO.FileMode mode, System.IO.FileOptions options)
    public static System.IO.FileStream Open(string path, System.IO.FileMode mode, System.IO.FileAccess access)
+   public static System.IO.FileStream Open(string path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileOptions options)
    public static System.IO.FileStream Open(string path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share)
+   public static System.IO.FileStream Open(string path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share, System.IO.FileOptions options)
    public static System.IO.FileStream OpenRead(string path) { throw null; }
+   public static System.IO.FileStream OpenRead(string path, System.IO.FileOptions options) { throw null; }
    public static System.IO.StreamReader OpenText(string path) { throw null; }
+   public static System.IO.StreamReader OpenText(string path, System.IO.FileOptions options) { throw null; }
    public static System.IO.FileStream OpenWrite(string path) { throw null; }
+   public static System.IO.FileStream OpenWrite(string path, System.IO.FileOptions options) { throw null; }
}note that File.Create(string path, int bufferSize, System.IO.FileOptions options) already exists.
public sealed partial class FileInfo : System.IO.FileSystemInfo
{
    public StreamWriter AppendText()
+   public StreamWriter AppendText(FileOptions options)
    public System.IO.FileStream Create()
+   public System.IO.FileStream Create(System.IO.FileOptions options)
    public System.IO.StreamWriter CreateText()
+   public System.IO.StreamWriter CreateText(System.IO.FileOptions options)
    public System.IO.FileStream Open(System.IO.FileMode mode)
+   public System.IO.FileStream Open(System.IO.FileMode mode, System.IO.FileOptions options)
    public System.IO.FileStream Open(System.IO.FileMode mode, System.IO.FileAccess access)
+   public System.IO.FileStream Open(System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileOptions options)
    public System.IO.FileStream Open(System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share)
+   public System.IO.FileStream Open(System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share, System.IO.FileOptions options)
    public System.IO.FileStream OpenRead()
+   public System.IO.FileStream OpenRead(System.IO.FileOptions options)
    public System.IO.StreamReader OpenText()
+   public System.IO.StreamReader OpenText(System.IO.FileOptions options)    
    public System.IO.FileStream OpenWrite()
+   public System.IO.FileStream OpenWrite(System.IO.FileOptions options)
}public partial class StreamReader : System.IO.TextReader
{
    public StreamReader(string path)
+   public StreamReader(string path, System.IO.FileOptions options)
    public StreamReader(string path, bool detectEncodingFromByteOrderMarks)
+   public StreamReader(string path, bool detectEncodingFromByteOrderMarks, System.IO.FileOptions options)
    public StreamReader(string path, System.Text.Encoding encoding)
+   public StreamReader(string path, System.Text.Encoding encoding, System.IO.FileOptions options)
    public StreamReader(string path, System.Text.Encoding encoding, bool detectEncodingFromByteOrderMarks)
+   public StreamReader(string path, System.Text.Encoding encoding, bool detectEncodingFromByteOrderMarks, System.IO.FileOptions options)
    public StreamReader(string path, System.Text.Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize)
+   public StreamReader(string path, System.Text.Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize, System.IO.FileOptions options)
}public partial class StreamWriter : System.IO.TextWriter
{
    public StreamWriter(string path)
+   public StreamWriter(string path, System.IO.FileOptions options)
    public StreamWriter(string path, bool append)
+   public StreamWriter(string path, bool append, System.IO.FileOptions options)
    public StreamWriter(string path, bool append, System.Text.Encoding encoding)
+   public StreamWriter(string path, bool append, System.Text.Encoding encoding, System.IO.FileOptions options)
    public StreamWriter(string path, bool append, System.Text.Encoding encoding, int bufferSize)
+   public StreamWriter(string path, bool append, System.Text.Encoding encoding, int bufferSize, System.IO.FileOptions options)
}Usage Examples
using FileStream filestream = File.OpenRead(Path.GetTempFileName(), FileOptions.Asynchronous);
byte[] bytes = Encoding.Unicode.GetBytes("example text to write");
await filestream.WriteAsync(bytes, 0, bytes.Length);Alternative Designs
In the beginning an idea was put for exposing additional async API methods next to the existing methods and that would return return the stream in a Task / ValueTask and guide the developer immediately into the async environment, also taken into account that a lot of .NET Native only exposed async variants in the API's with IO file streams.
However as was mentioned in comments that streams are opened with constructors and would require a lot of changes and provide no additional benefit and more overhead.