Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update FileStream.Position breaking change #40776

Merged
merged 2 commits into from
May 9, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,10 @@ ms.date: 10/04/2022

## Change description

In previous .NET versions on Windows, <xref:System.IO.FileStream.Position?displayProperty=nameWithType> is updated after the asynchronous read or write operation starts. Starting in .NET 6, <xref:System.IO.FileStream.Position?displayProperty=nameWithType> is updated after those operations complete.
In previous .NET versions on Windows, <xref:System.IO.FileStream.Position?displayProperty=nameWithType> was updated after the asynchronous read or write operation started. Starting in .NET 6, <xref:System.IO.FileStream.Position?displayProperty=nameWithType> is updated optimistically:

The following code shows how the value of <xref:System.IO.FileStream.Position?displayProperty=nameWithType> differs between previous .NET versions and .NET 6.

```csharp
byte[] bytes = new byte[10_000];
string path = Path.Combine(Path.GetTempPath(), Path.GetTempFileName());

using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None, bufferSize: 4096, useAsync: true))
{
Task[] writes = new Task[3];

writes[0] = fs.WriteAsync(bytes, 0, bytes.Length);
Console.WriteLine(fs.Position); // 10000 in .NET 5, 0 in .NET 6

writes[1] = fs.WriteAsync(bytes, 0, bytes.Length);
Console.WriteLine(fs.Position); // 20000 in .NET 5, 0 in .NET 6

writes[2] = fs.WriteAsync(bytes, 0, bytes.Length);
Console.WriteLine(fs.Position); // 30000 in .NET 5, 0 in .NET 6

await Task.WhenAll(writes);
Console.WriteLine(fs.Position); // 30000 in all versions
}
```
- After <xref:System.IO.FileStream.WriteAsync%2A> starts, but if the operation fails or is canceled, the position is corrected.
- When <xref:System.IO.FileStream.ReadAsync%2A> starts, but if the entire buffer isn't read, the position is corrected after the operation completes.

## Version introduced

Expand All @@ -48,11 +27,9 @@ This change was introduced to allow for 100% asynchronous file I/O with <xref:Sy
- [FileStream.FlushAsync ends up doing synchronous writes](https://github.com/dotnet/runtime/issues/27643)
- [Win32 FileStream turns async reads into sync reads](https://github.com/dotnet/runtime/issues/16341)

Now, when buffering is enabled (that is, the `bufferSize` argument that's passed to the [FileStream constructor](xref:System.IO.FileStream.%23ctor%2A) is greater than 1), every <xref:System.IO.FileStream.ReadAsync%2A> and <xref:System.IO.FileStream.WriteAsync%2A> operation is serialized.

## Recommended action

- Modify any code that relied on the position being set before operations completed.
- If you rely on <xref:System.IO.FileStream.Position?displayProperty=nameWithType> being set before the read or write starts because your code performs *parallel* reads or writes, you should switch to use the <xref:System.IO.RandomAccess?displayProperty=fullName> API instead. The <xref:System.IO.RandomAccess> API is designed for parallel file operations.

- To enable the .NET 5 behavior in .NET 6, specify an `AppContext` switch or an environment variable. By setting the switch to `true`, you opt out of all performance improvements made to `FileStream` in .NET 6.

Expand All @@ -68,7 +45,7 @@ Now, when buffering is enabled (that is, the `bufferSize` argument that's passed
set DOTNET_SYSTEM_IO_USENET5COMPATFILESTREAM=1
```

> [!NOTE]
> [!IMPORTANT]
> This switch is only available in .NET 6. It was [removed in .NET 7](../7.0/filestream-compat-switch.md).

## Affected APIs
Expand Down