C#idiomatic C#
using-async-for-file-accesscsharp/asynchronous-programming

Async and concurrency

Asynchronous file access

Learn how to use the async feature to access files in C#. You can call into asynchronous methods without using callbacks or splitting your code across methods.

  • page csharp/asynchronous-programming/using-async-for-file-access
  • updated 04/22/2026

By using the async feature to access files, you can call into asynchronous methods without using callbacks or splitting your code across multiple methods or lambda expressions. To make synchronous code asynchronous, call an asynchronous method instead of a synchronous method and add a few keywords to the code.

Consider adding asynchrony to file access calls for these reasons:

  • Asynchrony makes UI applications more responsive because the UI thread that launches the operation can perform other work. If the UI thread must execute code that takes a long time (for example, more than 50 milliseconds), the UI might freeze until the I/O is complete and the UI thread can again process keyboard and mouse input and other events.
  • Asynchrony improves the scalability of ASP.NET and other server-based applications by reducing the need for threads. If the application uses a dedicated thread per response and a thousand requests are being handled simultaneously, a thousand threads are needed. Asynchronous operations often don't need to use a thread during the wait. They use the existing I/O completion thread briefly at the end.
  • The latency of a file access operation might be very low under current conditions, but the latency might greatly increase in the future. For example, a file might be moved to a server that's across the world.
  • The added overhead of using the Async feature is small.
  • Multiple asynchronous I/O operations can run without blocking the calling thread.

Use appropriate classes

The simple examples in this topic demonstrate System.IO.File.WriteAllTextAsync and System.IO.File.ReadAllTextAsync. For fine control over the file I/O operations, use the System.IO.FileStream class, which has an option that causes asynchronous I/O to occur at the operating system level. By using this option, you can avoid blocking a thread pool thread in many cases. To enable this option, specify the useAsync=true or options=FileOptions.Asynchronous argument in the constructor call.

You can't use this option with System.IO.StreamReader and System.IO.StreamWriter if you open them directly by specifying a file path. However, you can use this option if you provide them a System.IO.Stream that the System.IO.FileStream class opened. Asynchronous calls are faster in UI apps even if a thread pool thread is blocked, because the UI thread isn't blocked during the wait.

Write text

The following examples write text to a file. At each await statement, the method immediately exits. When the file I/O is complete, the method resumes at the statement that follows the await statement. The async modifier is in the definition of methods that use the await statement.

Simple example

sample · csharpdocs/csharp/asynchronous-programming/snippets/file-access/Program.csSimpleWrite

csharp
using System.Text;

class Program
{
    static async Task Main()
    {
        await WriteText.Example.ProcessWriteAsync();
        await WriteText.Example.SimpleWriteAsync();

        await ReadText.Example.ProcessReadAsync();
        await ReadText.Example.SimpleReadAsync();

        await ParallelWriteText.Example.ProcessMultipleWritesAsync();
        await ParallelWriteText.Example.SimpleParallelWriteAsync();
    }
}

class WriteText
{
    public static WriteText Example = new WriteText();

    // <SimpleWrite>
    public async Task SimpleWriteAsync()
    {
        string filePath = "simple.txt";
        string text = $"Hello World";

        await File.WriteAllTextAsync(filePath, text);
    }
    // </SimpleWrite>

    // <WriteText>
    public async Task ProcessWriteAsync()
    {
        string filePath = "temp.txt";
        string text = $"Hello World{Environment.NewLine}";

        await WriteTextAsync(filePath, text);
    }

    async Task WriteTextAsync(string filePath, string text)
    {
        byte[] encodedText = Encoding.Unicode.GetBytes(text);

        using var sourceStream =
            new FileStream(
                filePath,
                FileMode.Create, FileAccess.Write, FileShare.None,
                bufferSize: 4096, useAsync: true);

        await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
    }
    // </WriteText>
}

class ReadText
{
    public static ReadText Example = new ReadText();

    // <SimpleRead>
    public async Task SimpleReadAsync()
    {
        string filePath = "simple.txt";
        string text = await File.ReadAllTextAsync(filePath);

        Console.WriteLine(text);
    }
    // </SimpleRead>

    // <ReadText>
    public async Task ProcessReadAsync()
    {
        try
        {
            string filePath = "temp.txt";
            if (File.Exists(filePath) != false)
            {
                string text = await ReadTextAsync(filePath);
                Console.WriteLine(text);
            }
            else
            {
                Console.WriteLine($"file not found: {filePath}");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

    async Task<string> ReadTextAsync(string filePath)
    {
        using var sourceStream =
            new FileStream(
                filePath,
                FileMode.Open, FileAccess.Read, FileShare.Read,
                bufferSize: 4096, useAsync: true);

        var sb = new StringBuilder();

        byte[] buffer = new byte[0x1000];
        int numRead;
        while ((numRead = await sourceStream.ReadAsync(buffer, 0, buffer.Length)) != 0)
        {
            string text = Encoding.Unicode.GetString(buffer, 0, numRead);
            sb.Append(text);
        }

        return sb.ToString();
    }
    // </ReadText>
}

class ParallelWriteText
{
    public static ParallelWriteText Example = new ParallelWriteText();

    // <SimpleParallelWrite>
    public async Task SimpleParallelWriteAsync()
    {
        string folder = Directory.CreateDirectory("tempfolder").Name;
        IList<Task> writeTaskList = new List<Task>();

        for (int index = 11; index <= 20; ++ index)
        {
            string fileName = $"file-{index:00}.txt";
            string filePath = $"{folder}/{fileName}";
            string text = $"In file {index}{Environment.NewLine}";

            writeTaskList.Add(File.WriteAllTextAsync(filePath, text));
        }

        await Task.WhenAll(writeTaskList);
    }
    // </SimpleParallelWrite>

    // <ParallelWriteText>
    public async Task ProcessMultipleWritesAsync()
    {
        IList<FileStream> sourceStreams = new List<FileStream>();

        try
        {
            string folder = Directory.CreateDirectory("tempfolder").Name;
            IList<Task> writeTaskList = new List<Task>();

            for (int index = 1; index <= 10; ++ index)
            {
                string fileName = $"file-{index:00}.txt";
                string filePath = $"{folder}/{fileName}";

                string text = $"In file {index}{Environment.NewLine}";
                byte[] encodedText = Encoding.Unicode.GetBytes(text);

                var sourceStream =
                    new FileStream(
                        filePath,
                        FileMode.Create, FileAccess.Write, FileShare.None,
                        bufferSize: 4096, useAsync: true);

                Task writeTask = sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
                sourceStreams.Add(sourceStream);

                writeTaskList.Add(writeTask);
            }

            await Task.WhenAll(writeTaskList);
        }
        finally
        {
            foreach (FileStream sourceStream in sourceStreams)
            {
                sourceStream.Close();
            }
        }
    }
    // </ParallelWriteText>
}

Finite control example

sample · csharpdocs/csharp/asynchronous-programming/snippets/file-access/Program.csWriteText

csharp
using System.Text;

class Program
{
    static async Task Main()
    {
        await WriteText.Example.ProcessWriteAsync();
        await WriteText.Example.SimpleWriteAsync();

        await ReadText.Example.ProcessReadAsync();
        await ReadText.Example.SimpleReadAsync();

        await ParallelWriteText.Example.ProcessMultipleWritesAsync();
        await ParallelWriteText.Example.SimpleParallelWriteAsync();
    }
}

class WriteText
{
    public static WriteText Example = new WriteText();

    // <SimpleWrite>
    public async Task SimpleWriteAsync()
    {
        string filePath = "simple.txt";
        string text = $"Hello World";

        await File.WriteAllTextAsync(filePath, text);
    }
    // </SimpleWrite>

    // <WriteText>
    public async Task ProcessWriteAsync()
    {
        string filePath = "temp.txt";
        string text = $"Hello World{Environment.NewLine}";

        await WriteTextAsync(filePath, text);
    }

    async Task WriteTextAsync(string filePath, string text)
    {
        byte[] encodedText = Encoding.Unicode.GetBytes(text);

        using var sourceStream =
            new FileStream(
                filePath,
                FileMode.Create, FileAccess.Write, FileShare.None,
                bufferSize: 4096, useAsync: true);

        await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
    }
    // </WriteText>
}

class ReadText
{
    public static ReadText Example = new ReadText();

    // <SimpleRead>
    public async Task SimpleReadAsync()
    {
        string filePath = "simple.txt";
        string text = await File.ReadAllTextAsync(filePath);

        Console.WriteLine(text);
    }
    // </SimpleRead>

    // <ReadText>
    public async Task ProcessReadAsync()
    {
        try
        {
            string filePath = "temp.txt";
            if (File.Exists(filePath) != false)
            {
                string text = await ReadTextAsync(filePath);
                Console.WriteLine(text);
            }
            else
            {
                Console.WriteLine($"file not found: {filePath}");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

    async Task<string> ReadTextAsync(string filePath)
    {
        using var sourceStream =
            new FileStream(
                filePath,
                FileMode.Open, FileAccess.Read, FileShare.Read,
                bufferSize: 4096, useAsync: true);

        var sb = new StringBuilder();

        byte[] buffer = new byte[0x1000];
        int numRead;
        while ((numRead = await sourceStream.ReadAsync(buffer, 0, buffer.Length)) != 0)
        {
            string text = Encoding.Unicode.GetString(buffer, 0, numRead);
            sb.Append(text);
        }

        return sb.ToString();
    }
    // </ReadText>
}

class ParallelWriteText
{
    public static ParallelWriteText Example = new ParallelWriteText();

    // <SimpleParallelWrite>
    public async Task SimpleParallelWriteAsync()
    {
        string folder = Directory.CreateDirectory("tempfolder").Name;
        IList<Task> writeTaskList = new List<Task>();

        for (int index = 11; index <= 20; ++ index)
        {
            string fileName = $"file-{index:00}.txt";
            string filePath = $"{folder}/{fileName}";
            string text = $"In file {index}{Environment.NewLine}";

            writeTaskList.Add(File.WriteAllTextAsync(filePath, text));
        }

        await Task.WhenAll(writeTaskList);
    }
    // </SimpleParallelWrite>

    // <ParallelWriteText>
    public async Task ProcessMultipleWritesAsync()
    {
        IList<FileStream> sourceStreams = new List<FileStream>();

        try
        {
            string folder = Directory.CreateDirectory("tempfolder").Name;
            IList<Task> writeTaskList = new List<Task>();

            for (int index = 1; index <= 10; ++ index)
            {
                string fileName = $"file-{index:00}.txt";
                string filePath = $"{folder}/{fileName}";

                string text = $"In file {index}{Environment.NewLine}";
                byte[] encodedText = Encoding.Unicode.GetBytes(text);

                var sourceStream =
                    new FileStream(
                        filePath,
                        FileMode.Create, FileAccess.Write, FileShare.None,
                        bufferSize: 4096, useAsync: true);

                Task writeTask = sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
                sourceStreams.Add(sourceStream);

                writeTaskList.Add(writeTask);
            }

            await Task.WhenAll(writeTaskList);
        }
        finally
        {
            foreach (FileStream sourceStream in sourceStreams)
            {
                sourceStream.Close();
            }
        }
    }
    // </ParallelWriteText>
}

The original example has the statement await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);, which is a contraction of the following two statements:

csharp
Task theTask = sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
await theTask;

The first statement returns a task and causes file processing to start. The second statement with the await causes the method to immediately exit and return a different task. When the file processing later completes, execution returns to the statement that follows the await.

Read text

The following examples read text from a file.

Simple example

sample · csharpdocs/csharp/asynchronous-programming/snippets/file-access/Program.csSimpleRead

csharp
using System.Text;

class Program
{
    static async Task Main()
    {
        await WriteText.Example.ProcessWriteAsync();
        await WriteText.Example.SimpleWriteAsync();

        await ReadText.Example.ProcessReadAsync();
        await ReadText.Example.SimpleReadAsync();

        await ParallelWriteText.Example.ProcessMultipleWritesAsync();
        await ParallelWriteText.Example.SimpleParallelWriteAsync();
    }
}

class WriteText
{
    public static WriteText Example = new WriteText();

    // <SimpleWrite>
    public async Task SimpleWriteAsync()
    {
        string filePath = "simple.txt";
        string text = $"Hello World";

        await File.WriteAllTextAsync(filePath, text);
    }
    // </SimpleWrite>

    // <WriteText>
    public async Task ProcessWriteAsync()
    {
        string filePath = "temp.txt";
        string text = $"Hello World{Environment.NewLine}";

        await WriteTextAsync(filePath, text);
    }

    async Task WriteTextAsync(string filePath, string text)
    {
        byte[] encodedText = Encoding.Unicode.GetBytes(text);

        using var sourceStream =
            new FileStream(
                filePath,
                FileMode.Create, FileAccess.Write, FileShare.None,
                bufferSize: 4096, useAsync: true);

        await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
    }
    // </WriteText>
}

class ReadText
{
    public static ReadText Example = new ReadText();

    // <SimpleRead>
    public async Task SimpleReadAsync()
    {
        string filePath = "simple.txt";
        string text = await File.ReadAllTextAsync(filePath);

        Console.WriteLine(text);
    }
    // </SimpleRead>

    // <ReadText>
    public async Task ProcessReadAsync()
    {
        try
        {
            string filePath = "temp.txt";
            if (File.Exists(filePath) != false)
            {
                string text = await ReadTextAsync(filePath);
                Console.WriteLine(text);
            }
            else
            {
                Console.WriteLine($"file not found: {filePath}");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

    async Task<string> ReadTextAsync(string filePath)
    {
        using var sourceStream =
            new FileStream(
                filePath,
                FileMode.Open, FileAccess.Read, FileShare.Read,
                bufferSize: 4096, useAsync: true);

        var sb = new StringBuilder();

        byte[] buffer = new byte[0x1000];
        int numRead;
        while ((numRead = await sourceStream.ReadAsync(buffer, 0, buffer.Length)) != 0)
        {
            string text = Encoding.Unicode.GetString(buffer, 0, numRead);
            sb.Append(text);
        }

        return sb.ToString();
    }
    // </ReadText>
}

class ParallelWriteText
{
    public static ParallelWriteText Example = new ParallelWriteText();

    // <SimpleParallelWrite>
    public async Task SimpleParallelWriteAsync()
    {
        string folder = Directory.CreateDirectory("tempfolder").Name;
        IList<Task> writeTaskList = new List<Task>();

        for (int index = 11; index <= 20; ++ index)
        {
            string fileName = $"file-{index:00}.txt";
            string filePath = $"{folder}/{fileName}";
            string text = $"In file {index}{Environment.NewLine}";

            writeTaskList.Add(File.WriteAllTextAsync(filePath, text));
        }

        await Task.WhenAll(writeTaskList);
    }
    // </SimpleParallelWrite>

    // <ParallelWriteText>
    public async Task ProcessMultipleWritesAsync()
    {
        IList<FileStream> sourceStreams = new List<FileStream>();

        try
        {
            string folder = Directory.CreateDirectory("tempfolder").Name;
            IList<Task> writeTaskList = new List<Task>();

            for (int index = 1; index <= 10; ++ index)
            {
                string fileName = $"file-{index:00}.txt";
                string filePath = $"{folder}/{fileName}";

                string text = $"In file {index}{Environment.NewLine}";
                byte[] encodedText = Encoding.Unicode.GetBytes(text);

                var sourceStream =
                    new FileStream(
                        filePath,
                        FileMode.Create, FileAccess.Write, FileShare.None,
                        bufferSize: 4096, useAsync: true);

                Task writeTask = sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
                sourceStreams.Add(sourceStream);

                writeTaskList.Add(writeTask);
            }

            await Task.WhenAll(writeTaskList);
        }
        finally
        {
            foreach (FileStream sourceStream in sourceStreams)
            {
                sourceStream.Close();
            }
        }
    }
    // </ParallelWriteText>
}

Finite control example

The text is buffered and, in this case, placed into a System.Text.StringBuilder. Unlike in the previous example, the evaluation of the await produces a value. The System.IO.Stream.ReadAsync method returns a System.Threading.Tasks.Task<System.Int32>, so the evaluation of the await produces an Int32 value numRead after the operation completes. For more information, see Async Return Types (C#).

sample · csharpdocs/csharp/asynchronous-programming/snippets/file-access/Program.csReadText

csharp
using System.Text;

class Program
{
    static async Task Main()
    {
        await WriteText.Example.ProcessWriteAsync();
        await WriteText.Example.SimpleWriteAsync();

        await ReadText.Example.ProcessReadAsync();
        await ReadText.Example.SimpleReadAsync();

        await ParallelWriteText.Example.ProcessMultipleWritesAsync();
        await ParallelWriteText.Example.SimpleParallelWriteAsync();
    }
}

class WriteText
{
    public static WriteText Example = new WriteText();

    // <SimpleWrite>
    public async Task SimpleWriteAsync()
    {
        string filePath = "simple.txt";
        string text = $"Hello World";

        await File.WriteAllTextAsync(filePath, text);
    }
    // </SimpleWrite>

    // <WriteText>
    public async Task ProcessWriteAsync()
    {
        string filePath = "temp.txt";
        string text = $"Hello World{Environment.NewLine}";

        await WriteTextAsync(filePath, text);
    }

    async Task WriteTextAsync(string filePath, string text)
    {
        byte[] encodedText = Encoding.Unicode.GetBytes(text);

        using var sourceStream =
            new FileStream(
                filePath,
                FileMode.Create, FileAccess.Write, FileShare.None,
                bufferSize: 4096, useAsync: true);

        await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
    }
    // </WriteText>
}

class ReadText
{
    public static ReadText Example = new ReadText();

    // <SimpleRead>
    public async Task SimpleReadAsync()
    {
        string filePath = "simple.txt";
        string text = await File.ReadAllTextAsync(filePath);

        Console.WriteLine(text);
    }
    // </SimpleRead>

    // <ReadText>
    public async Task ProcessReadAsync()
    {
        try
        {
            string filePath = "temp.txt";
            if (File.Exists(filePath) != false)
            {
                string text = await ReadTextAsync(filePath);
                Console.WriteLine(text);
            }
            else
            {
                Console.WriteLine($"file not found: {filePath}");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

    async Task<string> ReadTextAsync(string filePath)
    {
        using var sourceStream =
            new FileStream(
                filePath,
                FileMode.Open, FileAccess.Read, FileShare.Read,
                bufferSize: 4096, useAsync: true);

        var sb = new StringBuilder();

        byte[] buffer = new byte[0x1000];
        int numRead;
        while ((numRead = await sourceStream.ReadAsync(buffer, 0, buffer.Length)) != 0)
        {
            string text = Encoding.Unicode.GetString(buffer, 0, numRead);
            sb.Append(text);
        }

        return sb.ToString();
    }
    // </ReadText>
}

class ParallelWriteText
{
    public static ParallelWriteText Example = new ParallelWriteText();

    // <SimpleParallelWrite>
    public async Task SimpleParallelWriteAsync()
    {
        string folder = Directory.CreateDirectory("tempfolder").Name;
        IList<Task> writeTaskList = new List<Task>();

        for (int index = 11; index <= 20; ++ index)
        {
            string fileName = $"file-{index:00}.txt";
            string filePath = $"{folder}/{fileName}";
            string text = $"In file {index}{Environment.NewLine}";

            writeTaskList.Add(File.WriteAllTextAsync(filePath, text));
        }

        await Task.WhenAll(writeTaskList);
    }
    // </SimpleParallelWrite>

    // <ParallelWriteText>
    public async Task ProcessMultipleWritesAsync()
    {
        IList<FileStream> sourceStreams = new List<FileStream>();

        try
        {
            string folder = Directory.CreateDirectory("tempfolder").Name;
            IList<Task> writeTaskList = new List<Task>();

            for (int index = 1; index <= 10; ++ index)
            {
                string fileName = $"file-{index:00}.txt";
                string filePath = $"{folder}/{fileName}";

                string text = $"In file {index}{Environment.NewLine}";
                byte[] encodedText = Encoding.Unicode.GetBytes(text);

                var sourceStream =
                    new FileStream(
                        filePath,
                        FileMode.Create, FileAccess.Write, FileShare.None,
                        bufferSize: 4096, useAsync: true);

                Task writeTask = sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
                sourceStreams.Add(sourceStream);

                writeTaskList.Add(writeTask);
            }

            await Task.WhenAll(writeTaskList);
        }
        finally
        {
            foreach (FileStream sourceStream in sourceStreams)
            {
                sourceStream.Close();
            }
        }
    }
    // </ParallelWriteText>
}

Multiple asynchronous I/O operations

The following examples start multiple async write operations. The runtime queues these operations, and the underlying implementation might use operating system (OS) async I/O or thread pool threads depending on the platform and configuration, so actual concurrency depends on OS and hardware.

Simple example

sample · csharpdocs/csharp/asynchronous-programming/snippets/file-access/Program.csSimpleParallelWrite

csharp
using System.Text;

class Program
{
    static async Task Main()
    {
        await WriteText.Example.ProcessWriteAsync();
        await WriteText.Example.SimpleWriteAsync();

        await ReadText.Example.ProcessReadAsync();
        await ReadText.Example.SimpleReadAsync();

        await ParallelWriteText.Example.ProcessMultipleWritesAsync();
        await ParallelWriteText.Example.SimpleParallelWriteAsync();
    }
}

class WriteText
{
    public static WriteText Example = new WriteText();

    // <SimpleWrite>
    public async Task SimpleWriteAsync()
    {
        string filePath = "simple.txt";
        string text = $"Hello World";

        await File.WriteAllTextAsync(filePath, text);
    }
    // </SimpleWrite>

    // <WriteText>
    public async Task ProcessWriteAsync()
    {
        string filePath = "temp.txt";
        string text = $"Hello World{Environment.NewLine}";

        await WriteTextAsync(filePath, text);
    }

    async Task WriteTextAsync(string filePath, string text)
    {
        byte[] encodedText = Encoding.Unicode.GetBytes(text);

        using var sourceStream =
            new FileStream(
                filePath,
                FileMode.Create, FileAccess.Write, FileShare.None,
                bufferSize: 4096, useAsync: true);

        await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
    }
    // </WriteText>
}

class ReadText
{
    public static ReadText Example = new ReadText();

    // <SimpleRead>
    public async Task SimpleReadAsync()
    {
        string filePath = "simple.txt";
        string text = await File.ReadAllTextAsync(filePath);

        Console.WriteLine(text);
    }
    // </SimpleRead>

    // <ReadText>
    public async Task ProcessReadAsync()
    {
        try
        {
            string filePath = "temp.txt";
            if (File.Exists(filePath) != false)
            {
                string text = await ReadTextAsync(filePath);
                Console.WriteLine(text);
            }
            else
            {
                Console.WriteLine($"file not found: {filePath}");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

    async Task<string> ReadTextAsync(string filePath)
    {
        using var sourceStream =
            new FileStream(
                filePath,
                FileMode.Open, FileAccess.Read, FileShare.Read,
                bufferSize: 4096, useAsync: true);

        var sb = new StringBuilder();

        byte[] buffer = new byte[0x1000];
        int numRead;
        while ((numRead = await sourceStream.ReadAsync(buffer, 0, buffer.Length)) != 0)
        {
            string text = Encoding.Unicode.GetString(buffer, 0, numRead);
            sb.Append(text);
        }

        return sb.ToString();
    }
    // </ReadText>
}

class ParallelWriteText
{
    public static ParallelWriteText Example = new ParallelWriteText();

    // <SimpleParallelWrite>
    public async Task SimpleParallelWriteAsync()
    {
        string folder = Directory.CreateDirectory("tempfolder").Name;
        IList<Task> writeTaskList = new List<Task>();

        for (int index = 11; index <= 20; ++ index)
        {
            string fileName = $"file-{index:00}.txt";
            string filePath = $"{folder}/{fileName}";
            string text = $"In file {index}{Environment.NewLine}";

            writeTaskList.Add(File.WriteAllTextAsync(filePath, text));
        }

        await Task.WhenAll(writeTaskList);
    }
    // </SimpleParallelWrite>

    // <ParallelWriteText>
    public async Task ProcessMultipleWritesAsync()
    {
        IList<FileStream> sourceStreams = new List<FileStream>();

        try
        {
            string folder = Directory.CreateDirectory("tempfolder").Name;
            IList<Task> writeTaskList = new List<Task>();

            for (int index = 1; index <= 10; ++ index)
            {
                string fileName = $"file-{index:00}.txt";
                string filePath = $"{folder}/{fileName}";

                string text = $"In file {index}{Environment.NewLine}";
                byte[] encodedText = Encoding.Unicode.GetBytes(text);

                var sourceStream =
                    new FileStream(
                        filePath,
                        FileMode.Create, FileAccess.Write, FileShare.None,
                        bufferSize: 4096, useAsync: true);

                Task writeTask = sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
                sourceStreams.Add(sourceStream);

                writeTaskList.Add(writeTask);
            }

            await Task.WhenAll(writeTaskList);
        }
        finally
        {
            foreach (FileStream sourceStream in sourceStreams)
            {
                sourceStream.Close();
            }
        }
    }
    // </ParallelWriteText>
}

Finite control example

For each file, the System.IO.Stream.WriteAsync method returns a task that's added to a list of tasks. The await Task.WhenAll(tasks); statement exits the method and resumes within the method when file processing is complete for all of the tasks.

The example closes all System.IO.FileStream instances in a finally block after the tasks are complete. If each FileStream was instead created in a using statement, the FileStream might be disposed of before the task was complete.

The async approach avoids blocking the calling thread while I/O is pending. In many cases, throughput improvements depend on the OS, the hardware, and, on some platforms, .NET runtime behavior such as thread pool limits and scheduling.

sample · csharpdocs/csharp/asynchronous-programming/snippets/file-access/Program.csParallelWriteText

csharp
using System.Text;

class Program
{
    static async Task Main()
    {
        await WriteText.Example.ProcessWriteAsync();
        await WriteText.Example.SimpleWriteAsync();

        await ReadText.Example.ProcessReadAsync();
        await ReadText.Example.SimpleReadAsync();

        await ParallelWriteText.Example.ProcessMultipleWritesAsync();
        await ParallelWriteText.Example.SimpleParallelWriteAsync();
    }
}

class WriteText
{
    public static WriteText Example = new WriteText();

    // <SimpleWrite>
    public async Task SimpleWriteAsync()
    {
        string filePath = "simple.txt";
        string text = $"Hello World";

        await File.WriteAllTextAsync(filePath, text);
    }
    // </SimpleWrite>

    // <WriteText>
    public async Task ProcessWriteAsync()
    {
        string filePath = "temp.txt";
        string text = $"Hello World{Environment.NewLine}";

        await WriteTextAsync(filePath, text);
    }

    async Task WriteTextAsync(string filePath, string text)
    {
        byte[] encodedText = Encoding.Unicode.GetBytes(text);

        using var sourceStream =
            new FileStream(
                filePath,
                FileMode.Create, FileAccess.Write, FileShare.None,
                bufferSize: 4096, useAsync: true);

        await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
    }
    // </WriteText>
}

class ReadText
{
    public static ReadText Example = new ReadText();

    // <SimpleRead>
    public async Task SimpleReadAsync()
    {
        string filePath = "simple.txt";
        string text = await File.ReadAllTextAsync(filePath);

        Console.WriteLine(text);
    }
    // </SimpleRead>

    // <ReadText>
    public async Task ProcessReadAsync()
    {
        try
        {
            string filePath = "temp.txt";
            if (File.Exists(filePath) != false)
            {
                string text = await ReadTextAsync(filePath);
                Console.WriteLine(text);
            }
            else
            {
                Console.WriteLine($"file not found: {filePath}");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

    async Task<string> ReadTextAsync(string filePath)
    {
        using var sourceStream =
            new FileStream(
                filePath,
                FileMode.Open, FileAccess.Read, FileShare.Read,
                bufferSize: 4096, useAsync: true);

        var sb = new StringBuilder();

        byte[] buffer = new byte[0x1000];
        int numRead;
        while ((numRead = await sourceStream.ReadAsync(buffer, 0, buffer.Length)) != 0)
        {
            string text = Encoding.Unicode.GetString(buffer, 0, numRead);
            sb.Append(text);
        }

        return sb.ToString();
    }
    // </ReadText>
}

class ParallelWriteText
{
    public static ParallelWriteText Example = new ParallelWriteText();

    // <SimpleParallelWrite>
    public async Task SimpleParallelWriteAsync()
    {
        string folder = Directory.CreateDirectory("tempfolder").Name;
        IList<Task> writeTaskList = new List<Task>();

        for (int index = 11; index <= 20; ++ index)
        {
            string fileName = $"file-{index:00}.txt";
            string filePath = $"{folder}/{fileName}";
            string text = $"In file {index}{Environment.NewLine}";

            writeTaskList.Add(File.WriteAllTextAsync(filePath, text));
        }

        await Task.WhenAll(writeTaskList);
    }
    // </SimpleParallelWrite>

    // <ParallelWriteText>
    public async Task ProcessMultipleWritesAsync()
    {
        IList<FileStream> sourceStreams = new List<FileStream>();

        try
        {
            string folder = Directory.CreateDirectory("tempfolder").Name;
            IList<Task> writeTaskList = new List<Task>();

            for (int index = 1; index <= 10; ++ index)
            {
                string fileName = $"file-{index:00}.txt";
                string filePath = $"{folder}/{fileName}";

                string text = $"In file {index}{Environment.NewLine}";
                byte[] encodedText = Encoding.Unicode.GetBytes(text);

                var sourceStream =
                    new FileStream(
                        filePath,
                        FileMode.Create, FileAccess.Write, FileShare.None,
                        bufferSize: 4096, useAsync: true);

                Task writeTask = sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
                sourceStreams.Add(sourceStream);

                writeTaskList.Add(writeTask);
            }

            await Task.WhenAll(writeTaskList);
        }
        finally
        {
            foreach (FileStream sourceStream in sourceStreams)
            {
                sourceStream.Close();
            }
        }
    }
    // </ParallelWriteText>
}

When using the System.IO.Stream.WriteAsync and System.IO.Stream.ReadAsync methods, you can specify a System.Threading.CancellationToken to cancel the operation mid-stream. For more information, see Cancellation in managed threads.

See also