Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 19 additions & 22 deletions src/Ramstack.FileSystem.Abstractions/VirtualFileExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,6 @@ namespace Ramstack.FileSystem;
/// </summary>
public static class VirtualFileExtensions
{
private static Encoding? s_utf8NoBom;

/// <summary>
/// Gets an instance of the <see cref="UTF8Encoding"/> without BOM.
/// </summary>
private static Encoding Utf8NoBom => s_utf8NoBom ??= new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);

/// <summary>
/// Asynchronously returns a <see cref="StreamReader"/> with <see cref="Encoding.UTF8"/>
/// character encoding that reads from the specified text file.
Expand All @@ -26,7 +19,7 @@ public static class VirtualFileExtensions
/// The result is a <see cref="StreamReader"/> that reads from the text file.
/// </returns>
public static ValueTask<StreamReader> OpenTextAsync(this VirtualFile file, CancellationToken cancellationToken = default) =>
file.OpenTextAsync(Encoding.UTF8, cancellationToken);
file.OpenTextAsync(encoding: null, cancellationToken);

/// <summary>
/// Asynchronously returns a <see cref="StreamReader"/> with the specified character encoding
Expand Down Expand Up @@ -67,7 +60,7 @@ public static ValueTask WriteAsync(this VirtualFile file, Stream stream, Cancell
/// containing the full text from the current file.
/// </returns>
public static ValueTask<string> ReadAllTextAsync(this VirtualFile file, CancellationToken cancellationToken = default) =>
ReadAllTextAsync(file, Encoding.UTF8, cancellationToken);
ReadAllTextAsync(file, encoding: null, cancellationToken);

/// <summary>
/// Asynchronously reads all the text in the current file with the specified encoding.
Expand All @@ -81,9 +74,15 @@ public static ValueTask<string> ReadAllTextAsync(this VirtualFile file, Cancella
/// </returns>
public static async ValueTask<string> ReadAllTextAsync(this VirtualFile file, Encoding? encoding, CancellationToken cancellationToken = default)
{
//
// Use a manual read loop since .NET 6 lacks a StreamReader.ReadToEndAsync overload that accepts a CancellationToken.
// This ensures the operation remains responsive to cancellation requests.
//

const int BufferSize = 4096;

var stream = await file.OpenReadAsync(cancellationToken).ConfigureAwait(false);
// ReSharper disable once UseAwaitUsing
using var stream = await file.OpenReadAsync(cancellationToken).ConfigureAwait(false);
var reader = new StreamReader(stream, encoding ??= Encoding.UTF8);
var buffer = (char[]?)null;

Expand Down Expand Up @@ -217,20 +216,20 @@ static async ValueTask<byte[]> ReadAllBytesUnknownLengthImplAsync(Stream stream,
total += count;
}

static byte[] ResizeBuffer(byte[] bytes)
static byte[] ResizeBuffer(byte[] oldArray)
{
var length = (uint)bytes.Length * 2;
var length = (uint)oldArray.Length * 2;
if (length > (uint)Array.MaxLength)
length = (uint)Math.Max(Array.MaxLength, bytes.Length + 1);
length = (uint)Math.Max(Array.MaxLength, oldArray.Length + 1);

var tmp = ArrayPool<byte>.Shared.Rent((int)length);
Buffer.BlockCopy(bytes, 0, tmp, 0, bytes.Length);
var newArray = ArrayPool<byte>.Shared.Rent((int)length);
oldArray.AsSpan().TryCopyTo(newArray);

var rented = bytes;
bytes = tmp;
var rented = oldArray;
oldArray = newArray;

ArrayPool<byte>.Shared.Return(rented);
return bytes;
return oldArray;
}
}

Expand Down Expand Up @@ -302,7 +301,7 @@ public static ValueTask WriteAllTextAsync(this VirtualFile file, ReadOnlyMemory<
/// </returns>
public static async ValueTask WriteAllTextAsync(this VirtualFile file, ReadOnlyMemory<char> contents, Encoding? encoding, CancellationToken cancellationToken = default)
{
var stream = await file.OpenWriteAsync(cancellationToken).ConfigureAwait(false);
await using var stream = await file.OpenWriteAsync(cancellationToken).ConfigureAwait(false);
await using var writer = new StreamWriter(stream, encoding!);
await writer.WriteAsync(contents, cancellationToken).ConfigureAwait(false);
}
Expand Down Expand Up @@ -331,13 +330,11 @@ public static ValueTask WriteAllLinesAsync(this VirtualFile file, IEnumerable<st
/// </returns>
public static async ValueTask WriteAllLinesAsync(this VirtualFile file, IEnumerable<string> contents, Encoding? encoding, CancellationToken cancellationToken = default)
{
var stream = await file.OpenWriteAsync(cancellationToken).ConfigureAwait(false);
await using var stream = await file.OpenWriteAsync(cancellationToken).ConfigureAwait(false);
await using var writer = new StreamWriter(stream, encoding, bufferSize: -1, leaveOpen: false);

foreach (var line in contents)
await writer.WriteLineAsync(line).ConfigureAwait(false);

await writer.FlushAsync().ConfigureAwait(false);
}

/// <summary>
Expand Down
Loading