diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/File.cs b/src/libraries/System.Private.CoreLib/src/System/IO/File.cs
index 9326f6533306e4..2af095f40b439e 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IO/File.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/File.cs
@@ -632,6 +632,30 @@ public static string ReadAllText(string path, Encoding encoding)
public static void WriteAllText(string path, string? contents)
=> WriteAllText(path, contents, UTF8NoBOM);
+ ///
+ /// Creates a new file, writes the specified string to the file, and then closes the file.
+ /// If the target file already exists, it is truncated and overwritten.
+ ///
+ /// The file to write to.
+ /// The characters to write to the file.
+ /// is .
+ /// is empty.
+ /// The specified path, file name, or both exceed the system-defined maximum length.
+ /// The specified path is invalid (for example, it is on an unmapped drive).
+ /// An I/O error occurred while opening the file.
+ /// specified a file that is read-only.
+ /// specified a file that is hidden.
+ /// specified a directory.
+ /// This operation is not supported on the current platform.
+ /// The caller does not have the required permission.
+ /// is in an invalid format.
+ ///
+ /// This method uses UTF-8 encoding without a Byte-Order Mark (BOM), so using the GetPreamble method will return an empty byte array. If it is necessary to
+ /// include a UTF-8 identifier, such as a byte order mark, at the beginning of a file, use the method.
+ ///
+ public static void WriteAllText(string path, ReadOnlySpan contents)
+ => WriteAllText(path, contents, UTF8NoBOM);
+
public static void WriteAllText(string path, string? contents, Encoding encoding)
{
Validate(path, encoding);
@@ -639,6 +663,32 @@ public static void WriteAllText(string path, string? contents, Encoding encoding
WriteToFile(path, FileMode.Create, contents, encoding);
}
+ ///
+ /// Creates a new file, writes the specified string to the file using the specified encoding, and then closes the file.
+ /// If the target file already exists, it is truncated and overwritten.
+ ///
+ /// The file to write to.
+ /// The characters to write to the file.
+ /// The encoding to apply to the string.
+ /// is .
+ /// is empty.
+ /// is .
+ /// The specified path, file name, or both exceed the system-defined maximum length.
+ /// The specified path is invalid (for example, it is on an unmapped drive).
+ /// An I/O error occurred while opening the file.
+ /// specified a file that is read-only.
+ /// specified a file that is hidden.
+ /// specified a directory.
+ /// This operation is not supported on the current platform.
+ /// The caller does not have the required permission.
+ /// is in an invalid format.
+ public static void WriteAllText(string path, ReadOnlySpan contents, Encoding encoding)
+ {
+ Validate(path, encoding);
+
+ WriteToFile(path, FileMode.Create, contents, encoding);
+ }
+
public static byte[] ReadAllBytes(string path)
{
// SequentialScan is a perf hint that requires extra sys-call on non-Windows OSes.
@@ -682,9 +732,31 @@ public static byte[] ReadAllBytes(string path)
public static void WriteAllBytes(string path, byte[] bytes)
{
- ArgumentException.ThrowIfNullOrEmpty(path);
ArgumentNullException.ThrowIfNull(bytes);
+ WriteAllBytes(path, new ReadOnlySpan(bytes));
+ }
+
+ ///
+ /// Creates a new file, writes the specified byte array to the file, and then closes the file. If the target file already exists, it is truncated and overwritten.
+ ///
+ /// The file to write to.
+ /// The bytes to write to the file.
+ /// is null.
+ /// is empty.
+ /// The specified path, file name, or both exceed the system-defined maximum length.
+ /// The specified path is invalid (for example, it is on an unmapped drive).
+ /// An I/O error occurred while opening the file.
+ /// specified a file that is read-only.
+ /// specified a file that is hidden.
+ /// specified a directory.
+ /// The caller does not have the required permission.
+ /// This operation is not supported on the current platform.
+ /// is in an invalid format.
+ public static void WriteAllBytes(string path, ReadOnlySpan bytes)
+ {
+ ArgumentException.ThrowIfNullOrEmpty(path);
+
using SafeFileHandle sfh = OpenHandle(path, FileMode.Create, FileAccess.Write, FileShare.Read);
RandomAccess.WriteAtOffset(sfh, bytes, 0);
}
@@ -695,17 +767,46 @@ public static void WriteAllBytes(string path, byte[] bytes)
///
/// The file to append to.
/// The bytes to append to the file.
- ///
- /// is a zero-length string, contains only white space, or contains one more invalid characters defined by the method.
- ///
- ///
- /// Either or is null.
- ///
+ /// is null.
+ /// is null.
+ /// is empty.
+ /// The specified path, file name, or both exceed the system-defined maximum length.
+ /// The specified path is invalid (for example, it is on an unmapped drive).
+ /// An I/O error occurred while opening the file.
+ /// specified a file that is read-only.
+ /// specified a file that is hidden.
+ /// specified a directory.
+ /// The caller does not have the required permission.
+ /// This operation is not supported on the current platform.
+ /// is in an invalid format.
public static void AppendAllBytes(string path, byte[] bytes)
{
- ArgumentException.ThrowIfNullOrEmpty(path);
ArgumentNullException.ThrowIfNull(bytes);
+ AppendAllBytes(path, new ReadOnlySpan(bytes));
+ }
+
+ ///
+ /// Appends the specified byte array to the end of the file at the given path.
+ /// If the file doesn't exist, this method creates a new file.
+ ///
+ /// The file to append to.
+ /// The bytes to append to the file.
+ /// is null.
+ /// is empty.
+ /// The specified path, file name, or both exceed the system-defined maximum length.
+ /// The specified path is invalid (for example, it is on an unmapped drive).
+ /// An I/O error occurred while opening the file.
+ /// specified a file that is read-only.
+ /// specified a file that is hidden.
+ /// specified a directory.
+ /// The caller does not have the required permission.
+ /// This operation is not supported on the current platform.
+ /// is in an invalid format.
+ public static void AppendAllBytes(string path, ReadOnlySpan bytes)
+ {
+ ArgumentException.ThrowIfNullOrEmpty(path);
+
using SafeFileHandle fileHandle = OpenHandle(path, FileMode.Append, FileAccess.Write, FileShare.Read);
long fileOffset = RandomAccess.GetLength(fileHandle);
RandomAccess.WriteAtOffset(fileHandle, bytes, fileOffset);
@@ -717,27 +818,37 @@ public static void AppendAllBytes(string path, byte[] bytes)
///
/// The file to append to.
/// The bytes to append to the file.
- /// The token to monitor for cancellation requests. The default value is .
- /// A task that represents the asynchronous append operation.
- ///
- /// is a zero-length string, contains only white space, or contains one more invalid characters defined by the method.
- ///
- ///
- /// Either or is null.
- ///
- ///
- /// The cancellation token was canceled. This exception is stored into the returned task.
- ///
- public static Task AppendAllBytesAsync(string path, byte[] bytes, CancellationToken cancellationToken = default(CancellationToken))
+ /// The token to monitor for cancellation requests. The default value is .
+ /// is null.
+ /// is null.
+ /// is empty.
+ /// The cancellation token was canceled. This exception is stored into the returned task.
+ public static Task AppendAllBytesAsync(string path, byte[] bytes, CancellationToken cancellationToken = default)
{
- ArgumentException.ThrowIfNullOrEmpty(path);
ArgumentNullException.ThrowIfNull(bytes);
+ return AppendAllBytesAsync(path, new ReadOnlyMemory(bytes), cancellationToken);
+ }
+
+ ///
+ /// Asynchronously appends the specified byte array to the end of the file at the given path.
+ /// If the file doesn't exist, this method creates a new file. If the operation is canceled, the task will return in a canceled state.
+ ///
+ /// The file to append to.
+ /// The bytes to append to the file.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// is null.
+ /// is empty.
+ /// The cancellation token was canceled. This exception is stored into the returned task.
+ public static Task AppendAllBytesAsync(string path, ReadOnlyMemory bytes, CancellationToken cancellationToken = default)
+ {
+ ArgumentException.ThrowIfNullOrEmpty(path);
+
return cancellationToken.IsCancellationRequested
? Task.FromCanceled(cancellationToken)
: Core(path, bytes, cancellationToken);
- static async Task Core(string path, byte[] bytes, CancellationToken cancellationToken)
+ static async Task Core(string path, ReadOnlyMemory bytes, CancellationToken cancellationToken)
{
using SafeFileHandle fileHandle = OpenHandle(path, FileMode.Append, FileAccess.Write, FileShare.Read, FileOptions.Asynchronous);
long fileOffset = RandomAccess.GetLength(fileHandle);
@@ -831,6 +942,30 @@ private static void InternalWriteAllLines(StreamWriter writer, IEnumerable AppendAllText(path, contents, UTF8NoBOM);
+ ///
+ /// Appends the specified string to the file, creating the file if it does not already exist.
+ ///
+ /// The file to append to.
+ /// The characters to write to the file.
+ /// is .
+ /// is empty.
+ /// The specified path, file name, or both exceed the system-defined maximum length.
+ /// The specified path is invalid (for example, it is on an unmapped drive).
+ /// An I/O error occurred while opening the file.
+ /// specified a file that is read-only.
+ /// specified a file that is hidden.
+ /// specified a directory.
+ /// This operation is not supported on the current platform.
+ /// The caller does not have the required permission.
+ /// is in an invalid format.
+ ///
+ /// Given a string and a file path, this method opens the specified file, appends the string to the end of the file using the specified encoding,
+ /// and then closes the file. The file handle is guaranteed to be closed by this method, even if exceptions are raised. The method creates the file
+ /// if it doesn't exist, but it doesn't create new directories. Therefore, the value of the path parameter must contain existing directories.
+ ///
+ public static void AppendAllText(string path, ReadOnlySpan contents)
+ => AppendAllText(path, contents, UTF8NoBOM);
+
public static void AppendAllText(string path, string? contents, Encoding encoding)
{
Validate(path, encoding);
@@ -838,6 +973,36 @@ public static void AppendAllText(string path, string? contents, Encoding encodin
WriteToFile(path, FileMode.Append, contents, encoding);
}
+ ///
+ /// Appends the specified string to the file, creating the file if it does not already exist.
+ ///
+ /// The file to append to.
+ /// The characters to write to the file.
+ /// The encoding to apply to the string.
+ /// is .
+ /// is empty.
+ /// is .
+ /// The specified path, file name, or both exceed the system-defined maximum length.
+ /// The specified path is invalid (for example, it is on an unmapped drive).
+ /// An I/O error occurred while opening the file.
+ /// specified a file that is read-only.
+ /// specified a file that is hidden.
+ /// specified a directory.
+ /// This operation is not supported on the current platform.
+ /// The caller does not have the required permission.
+ /// is in an invalid format.
+ ///
+ /// Given a string and a file path, this method opens the specified file, appends the string to the end of the file using the specified encoding,
+ /// and then closes the file. The file handle is guaranteed to be closed by this method, even if exceptions are raised. The method creates the file
+ /// if it doesn't exist, but it doesn't create new directories. Therefore, the value of the path parameter must contain existing directories.
+ ///
+ public static void AppendAllText(string path, ReadOnlySpan contents, Encoding encoding)
+ {
+ Validate(path, encoding);
+
+ WriteToFile(path, FileMode.Append, contents, encoding);
+ }
+
public static void AppendAllLines(string path, IEnumerable contents)
=> AppendAllLines(path, contents, UTF8NoBOM);
@@ -911,10 +1076,10 @@ private static StreamReader AsyncStreamReader(string path, Encoding encoding)
new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, DefaultBufferSize, FileOptions.Asynchronous | FileOptions.SequentialScan),
encoding, detectEncodingFromByteOrderMarks: true);
- public static Task ReadAllTextAsync(string path, CancellationToken cancellationToken = default(CancellationToken))
+ public static Task ReadAllTextAsync(string path, CancellationToken cancellationToken = default)
=> ReadAllTextAsync(path, Encoding.UTF8, cancellationToken);
- public static Task ReadAllTextAsync(string path, Encoding encoding, CancellationToken cancellationToken = default(CancellationToken))
+ public static Task ReadAllTextAsync(string path, Encoding encoding, CancellationToken cancellationToken = default)
{
Validate(path, encoding);
@@ -956,10 +1121,35 @@ private static async Task InternalReadAllTextAsync(string path, Encoding
}
}
- public static Task WriteAllTextAsync(string path, string? contents, CancellationToken cancellationToken = default(CancellationToken))
+ public static Task WriteAllTextAsync(string path, string? contents, CancellationToken cancellationToken = default)
+ => WriteAllTextAsync(path, contents, UTF8NoBOM, cancellationToken);
+
+ ///
+ /// Asynchronously creates a new file, writes the specified string to the file, and then closes the file.
+ /// If the target file already exists, it is truncated and overwritten.
+ ///
+ /// The file to write to.
+ /// The characters to write to the file.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A task that represents the asynchronous write operation.
+ /// The cancellation token was canceled. This exception is stored into the returned task.
+ public static Task WriteAllTextAsync(string path, ReadOnlyMemory contents, CancellationToken cancellationToken = default)
=> WriteAllTextAsync(path, contents, UTF8NoBOM, cancellationToken);
- public static Task WriteAllTextAsync(string path, string? contents, Encoding encoding, CancellationToken cancellationToken = default(CancellationToken))
+ public static Task WriteAllTextAsync(string path, string? contents, Encoding encoding, CancellationToken cancellationToken = default)
+ => WriteAllTextAsync(path, contents.AsMemory(), encoding, cancellationToken);
+
+ ///
+ /// Asynchronously creates a new file, writes the specified string to the file using the specified encoding, and then closes the file.
+ /// If the target file already exists, it is truncated and overwritten.
+ ///
+ /// The file to write to.
+ /// The characters to write to the file.
+ /// The encoding to apply to the string.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A task that represents the asynchronous write operation.
+ /// The cancellation token was canceled. This exception is stored into the returned task.
+ public static Task WriteAllTextAsync(string path, ReadOnlyMemory contents, Encoding encoding, CancellationToken cancellationToken = default)
{
Validate(path, encoding);
@@ -971,7 +1161,7 @@ private static async Task InternalReadAllTextAsync(string path, Encoding
return WriteToFileAsync(path, FileMode.Create, contents, encoding, cancellationToken);
}
- public static Task ReadAllBytesAsync(string path, CancellationToken cancellationToken = default(CancellationToken))
+ public static Task ReadAllBytesAsync(string path, CancellationToken cancellationToken = default)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -1060,26 +1250,42 @@ private static async Task InternalReadAllBytesUnknownLengthAsync(SafeFil
}
}
- public static Task WriteAllBytesAsync(string path, byte[] bytes, CancellationToken cancellationToken = default(CancellationToken))
+ public static Task WriteAllBytesAsync(string path, byte[] bytes, CancellationToken cancellationToken = default)
{
- ArgumentException.ThrowIfNullOrEmpty(path);
ArgumentNullException.ThrowIfNull(bytes);
+ return WriteAllBytesAsync(path, new ReadOnlyMemory(bytes), cancellationToken);
+ }
+
+ ///
+ /// Asynchronously creates a new file, writes the specified byte array to the file, and then closes the file. If the target file already exists, it is truncated and overwritten.
+ ///
+ /// The file to write to.
+ /// The bytes to write to the file.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A task that represents the asynchronous write operation.
+ /// is null.
+ /// is empty.
+ /// The cancellation token was canceled. This exception is stored into the returned task.
+ public static Task WriteAllBytesAsync(string path, ReadOnlyMemory bytes, CancellationToken cancellationToken = default)
+ {
+ ArgumentException.ThrowIfNullOrEmpty(path);
+
return cancellationToken.IsCancellationRequested
? Task.FromCanceled(cancellationToken)
: Core(path, bytes, cancellationToken);
- static async Task Core(string path, byte[] bytes, CancellationToken cancellationToken)
+ static async Task Core(string path, ReadOnlyMemory bytes, CancellationToken cancellationToken)
{
using SafeFileHandle sfh = OpenHandle(path, FileMode.Create, FileAccess.Write, FileShare.Read, FileOptions.Asynchronous);
await RandomAccess.WriteAtOffsetAsync(sfh, bytes, 0, cancellationToken).ConfigureAwait(false);
}
}
- public static Task ReadAllLinesAsync(string path, CancellationToken cancellationToken = default(CancellationToken))
+ public static Task ReadAllLinesAsync(string path, CancellationToken cancellationToken = default)
=> ReadAllLinesAsync(path, Encoding.UTF8, cancellationToken);
- public static Task ReadAllLinesAsync(string path, Encoding encoding, CancellationToken cancellationToken = default(CancellationToken))
+ public static Task ReadAllLinesAsync(string path, Encoding encoding, CancellationToken cancellationToken = default)
{
Validate(path, encoding);
@@ -1108,10 +1314,10 @@ private static async Task InternalReadAllLinesAsync(string path, Encod
}
}
- public static Task WriteAllLinesAsync(string path, IEnumerable contents, CancellationToken cancellationToken = default(CancellationToken))
+ public static Task WriteAllLinesAsync(string path, IEnumerable contents, CancellationToken cancellationToken = default)
=> WriteAllLinesAsync(path, contents, UTF8NoBOM, cancellationToken);
- public static Task WriteAllLinesAsync(string path, IEnumerable contents, Encoding encoding, CancellationToken cancellationToken = default(CancellationToken)) =>
+ public static Task WriteAllLinesAsync(string path, IEnumerable contents, Encoding encoding, CancellationToken cancellationToken = default) =>
WriteAllLinesAsync(path, contents, encoding, append: false, cancellationToken);
private static Task WriteAllLinesAsync(string path, IEnumerable contents, Encoding encoding, bool append, CancellationToken cancellationToken)
@@ -1154,10 +1360,33 @@ private static async Task InternalWriteAllLinesAsync(StreamWriter writer, IEnume
}
}
- public static Task AppendAllTextAsync(string path, string? contents, CancellationToken cancellationToken = default(CancellationToken))
+ public static Task AppendAllTextAsync(string path, string? contents, CancellationToken cancellationToken = default)
+ => AppendAllTextAsync(path, contents, UTF8NoBOM, cancellationToken);
+
+ ///
+ /// Asynchronously opens a file or creates a file if it does not already exist, appends the specified string to the file, and then closes the file.
+ ///
+ /// The file to append the specified string to.
+ /// The characters to append to the file.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A task that represents the asynchronous append operation.
+ /// The cancellation token was canceled. This exception is stored into the returned task.
+ public static Task AppendAllTextAsync(string path, ReadOnlyMemory contents, CancellationToken cancellationToken = default)
=> AppendAllTextAsync(path, contents, UTF8NoBOM, cancellationToken);
- public static Task AppendAllTextAsync(string path, string? contents, Encoding encoding, CancellationToken cancellationToken = default(CancellationToken))
+ public static Task AppendAllTextAsync(string path, string? contents, Encoding encoding, CancellationToken cancellationToken = default)
+ => AppendAllTextAsync(path, contents.AsMemory(), encoding, cancellationToken);
+
+ ///
+ /// Asynchronously opens a file or creates the file if it does not already exist, appends the specified string to the file using the specified encoding, and then closes the file.
+ ///
+ /// The file to append the specified string to.
+ /// The characters to append to the file.
+ /// The character encoding to use.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// A task that represents the asynchronous append operation.
+ /// The cancellation token was canceled. This exception is stored into the returned task.
+ public static Task AppendAllTextAsync(string path, ReadOnlyMemory contents, Encoding encoding, CancellationToken cancellationToken = default)
{
Validate(path, encoding);
@@ -1169,10 +1398,10 @@ private static async Task InternalWriteAllLinesAsync(StreamWriter writer, IEnume
return WriteToFileAsync(path, FileMode.Append, contents, encoding, cancellationToken);
}
- public static Task AppendAllLinesAsync(string path, IEnumerable contents, CancellationToken cancellationToken = default(CancellationToken))
+ public static Task AppendAllLinesAsync(string path, IEnumerable contents, CancellationToken cancellationToken = default)
=> AppendAllLinesAsync(path, contents, UTF8NoBOM, cancellationToken);
- public static Task AppendAllLinesAsync(string path, IEnumerable contents, Encoding encoding, CancellationToken cancellationToken = default(CancellationToken)) =>
+ public static Task AppendAllLinesAsync(string path, IEnumerable contents, Encoding encoding, CancellationToken cancellationToken = default) =>
WriteAllLinesAsync(path, contents, encoding, append: true, cancellationToken);
///
@@ -1266,7 +1495,7 @@ private static byte[] ReadAllBytesUnknownLength(SafeFileHandle sfh)
}
}
- private static void WriteToFile(string path, FileMode mode, string? contents, Encoding encoding)
+ private static void WriteToFile(string path, FileMode mode, ReadOnlySpan contents, Encoding encoding)
{
ReadOnlySpan preamble = encoding.GetPreamble();
int preambleSize = preamble.Length;
@@ -1274,7 +1503,7 @@ private static void WriteToFile(string path, FileMode mode, string? contents, En
using SafeFileHandle fileHandle = OpenHandle(path, mode, FileAccess.Write, FileShare.Read, FileOptions.None, GetPreallocationSize(mode, contents, encoding, preambleSize));
long fileOffset = mode == FileMode.Append && fileHandle.CanSeek ? RandomAccess.GetLength(fileHandle) : 0;
- if (string.IsNullOrEmpty(contents))
+ if (contents.IsEmpty)
{
if (preambleSize > 0 // even if the content is empty, we want to store the preamble
&& fileOffset == 0) // if we're appending to a file that already has data, don't write the preamble.
@@ -1300,12 +1529,11 @@ private static void WriteToFile(string path, FileMode mode, string? contents, En
}
Encoder encoder = encoding.GetEncoder();
- ReadOnlySpan remaining = contents;
- while (!remaining.IsEmpty)
+ while (!contents.IsEmpty)
{
- ReadOnlySpan toEncode = remaining.Slice(0, Math.Min(remaining.Length, ChunkSize));
- remaining = remaining.Slice(toEncode.Length);
- int encoded = encoder.GetBytes(toEncode, bytes.Slice(preambleSize), flush: remaining.IsEmpty);
+ ReadOnlySpan toEncode = contents.Slice(0, Math.Min(contents.Length, ChunkSize));
+ contents = contents.Slice(toEncode.Length);
+ int encoded = encoder.GetBytes(toEncode, bytes.Slice(preambleSize), flush: contents.IsEmpty);
Span toStore = bytes.Slice(0, preambleSize + encoded);
RandomAccess.WriteAtOffset(fileHandle, toStore, fileOffset);
@@ -1323,15 +1551,15 @@ private static void WriteToFile(string path, FileMode mode, string? contents, En
}
}
- private static async Task WriteToFileAsync(string path, FileMode mode, string? contents, Encoding encoding, CancellationToken cancellationToken)
+ private static async Task WriteToFileAsync(string path, FileMode mode, ReadOnlyMemory contents, Encoding encoding, CancellationToken cancellationToken)
{
ReadOnlyMemory preamble = encoding.GetPreamble();
int preambleSize = preamble.Length;
- using SafeFileHandle fileHandle = OpenHandle(path, mode, FileAccess.Write, FileShare.Read, FileOptions.Asynchronous, GetPreallocationSize(mode, contents, encoding, preambleSize));
+ using SafeFileHandle fileHandle = OpenHandle(path, mode, FileAccess.Write, FileShare.Read, FileOptions.Asynchronous, GetPreallocationSize(mode, contents.Span, encoding, preambleSize));
long fileOffset = mode == FileMode.Append && fileHandle.CanSeek ? RandomAccess.GetLength(fileHandle) : 0;
- if (string.IsNullOrEmpty(contents))
+ if (contents.IsEmpty)
{
if (preambleSize > 0 // even if the content is empty, we want to store the preamble
&& fileOffset == 0) // if we're appending to a file that already has data, don't write the preamble.
@@ -1355,12 +1583,11 @@ private static async Task WriteToFileAsync(string path, FileMode mode, string? c
}
Encoder encoder = encoding.GetEncoder();
- ReadOnlyMemory remaining = contents.AsMemory();
- while (!remaining.IsEmpty)
+ while (!contents.IsEmpty)
{
- ReadOnlyMemory toEncode = remaining.Slice(0, Math.Min(remaining.Length, ChunkSize));
- remaining = remaining.Slice(toEncode.Length);
- int encoded = encoder.GetBytes(toEncode.Span, bytes.AsSpan(preambleSize), flush: remaining.IsEmpty);
+ ReadOnlyMemory toEncode = contents.Slice(0, Math.Min(contents.Length, ChunkSize));
+ contents = contents.Slice(toEncode.Length);
+ int encoded = encoder.GetBytes(toEncode.Span, bytes.AsSpan(preambleSize), flush: contents.IsEmpty);
ReadOnlyMemory toStore = new ReadOnlyMemory(bytes, 0, preambleSize + encoded);
await RandomAccess.WriteAtOffsetAsync(fileHandle, toStore, fileOffset, cancellationToken).ConfigureAwait(false);
@@ -1375,10 +1602,10 @@ private static async Task WriteToFileAsync(string path, FileMode mode, string? c
}
}
- private static long GetPreallocationSize(FileMode mode, string? contents, Encoding encoding, int preambleSize)
+ private static long GetPreallocationSize(FileMode mode, ReadOnlySpan contents, Encoding encoding, int preambleSize)
{
// for a single write operation, setting preallocationSize has no perf benefit, as it requires an additional sys-call
- if (contents is null || contents.Length < ChunkSize)
+ if (contents.Length < ChunkSize)
{
return 0;
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Windows.cs
index 151a0abfc84fac..6918da0413fc65 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Windows.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Windows.cs
@@ -279,7 +279,7 @@ private static unsafe (SafeFileHandle.OverlappedValueTaskSource? vts, int errorC
try
{
NativeOverlapped* nativeOverlapped = vts.PrepareForOperation(buffer, fileOffset, strategy);
- Debug.Assert(vts._memoryHandle.Pointer != null);
+ Debug.Assert(vts._memoryHandle.Pointer != null || buffer.IsEmpty);
// Queue an async ReadFile operation.
if (Interop.Kernel32.ReadFile(handle, (byte*)vts._memoryHandle.Pointer, buffer.Length, IntPtr.Zero, nativeOverlapped) == 0)
@@ -372,7 +372,7 @@ private static unsafe (SafeFileHandle.OverlappedValueTaskSource? vts, int errorC
try
{
NativeOverlapped* nativeOverlapped = vts.PrepareForOperation(buffer, fileOffset, strategy);
- Debug.Assert(vts._memoryHandle.Pointer != null);
+ Debug.Assert(vts._memoryHandle.Pointer != null || buffer.IsEmpty);
// Queue an async WriteFile operation.
if (Interop.Kernel32.WriteFile(handle, (byte*)vts._memoryHandle.Pointer, buffer.Length, IntPtr.Zero, nativeOverlapped) == 0)
diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs
index 2b03c0b011ff9e..8fe1d5c4448ae2 100644
--- a/src/libraries/System.Runtime/ref/System.Runtime.cs
+++ b/src/libraries/System.Runtime/ref/System.Runtime.cs
@@ -10089,15 +10089,21 @@ public EnumerationOptions() { }
public static partial class File
{
public static void AppendAllBytes(string path, byte[] bytes) { }
+ public static void AppendAllBytes(string path, System.ReadOnlySpan bytes) { }
public static System.Threading.Tasks.Task AppendAllBytesAsync(string path, byte[] bytes, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+ public static System.Threading.Tasks.Task AppendAllBytesAsync(string path, System.ReadOnlyMemory bytes, System.Threading.CancellationToken cancellationToken = default) { throw null; }
public static void AppendAllLines(string path, System.Collections.Generic.IEnumerable contents) { }
public static void AppendAllLines(string path, System.Collections.Generic.IEnumerable contents, System.Text.Encoding encoding) { }
public static System.Threading.Tasks.Task AppendAllLinesAsync(string path, System.Collections.Generic.IEnumerable contents, System.Text.Encoding encoding, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public static System.Threading.Tasks.Task AppendAllLinesAsync(string path, System.Collections.Generic.IEnumerable contents, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public static void AppendAllText(string path, string? contents) { }
public static void AppendAllText(string path, string? contents, System.Text.Encoding encoding) { }
+ public static void AppendAllText(string path, System.ReadOnlySpan contents) { }
+ public static void AppendAllText(string path, System.ReadOnlySpan contents, System.Text.Encoding encoding) { }
public static System.Threading.Tasks.Task AppendAllTextAsync(string path, string? contents, System.Text.Encoding encoding, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public static System.Threading.Tasks.Task AppendAllTextAsync(string path, string? contents, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+ public static System.Threading.Tasks.Task AppendAllTextAsync(string path, System.ReadOnlyMemory contents, System.Threading.CancellationToken cancellationToken = default) { throw null; }
+ public static System.Threading.Tasks.Task AppendAllTextAsync(string path, System.ReadOnlyMemory contents, System.Text.Encoding encoding, System.Threading.CancellationToken cancellationToken = default) { throw null; }
public static System.IO.StreamWriter AppendText(string path) { throw null; }
public static void Copy(string sourceFileName, string destFileName) { }
public static void Copy(string sourceFileName, string destFileName, bool overwrite) { }
@@ -10176,7 +10182,9 @@ public static void SetUnixFileMode(Microsoft.Win32.SafeHandles.SafeFileHandle fi
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("windows")]
public static void SetUnixFileMode(string path, System.IO.UnixFileMode mode) { }
public static void WriteAllBytes(string path, byte[] bytes) { }
+ public static void WriteAllBytes(string path, System.ReadOnlySpan bytes) { }
public static System.Threading.Tasks.Task WriteAllBytesAsync(string path, byte[] bytes, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+ public static System.Threading.Tasks.Task WriteAllBytesAsync(string path, System.ReadOnlyMemory bytes, System.Threading.CancellationToken cancellationToken = default) { throw null; }
public static void WriteAllLines(string path, System.Collections.Generic.IEnumerable contents) { }
public static void WriteAllLines(string path, System.Collections.Generic.IEnumerable contents, System.Text.Encoding encoding) { }
public static void WriteAllLines(string path, string[] contents) { }
@@ -10185,8 +10193,12 @@ public static void WriteAllLines(string path, string[] contents, System.Text.Enc
public static System.Threading.Tasks.Task WriteAllLinesAsync(string path, System.Collections.Generic.IEnumerable contents, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public static void WriteAllText(string path, string? contents) { }
public static void WriteAllText(string path, string? contents, System.Text.Encoding encoding) { }
+ public static void WriteAllText(string path, System.ReadOnlySpan contents) { }
+ public static void WriteAllText(string path, System.ReadOnlySpan contents, System.Text.Encoding encoding) { }
public static System.Threading.Tasks.Task WriteAllTextAsync(string path, string? contents, System.Text.Encoding encoding, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public static System.Threading.Tasks.Task WriteAllTextAsync(string path, string? contents, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+ public static System.Threading.Tasks.Task WriteAllTextAsync(string path, System.ReadOnlyMemory contents, System.Threading.CancellationToken cancellationToken = default) { throw null; }
+ public static System.Threading.Tasks.Task WriteAllTextAsync(string path, System.ReadOnlyMemory contents, System.Text.Encoding encoding, System.Threading.CancellationToken cancellationToken = default) { throw null; }
}
[System.FlagsAttribute]
public enum FileAccess
diff --git a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/Append.cs b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/Append.cs
index 68160715a7d635..aa2d1829a711a7 100644
--- a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/Append.cs
+++ b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/Append.cs
@@ -40,6 +40,21 @@ protected override void Write(string path, string content, Encoding encoding)
}
}
+ public class File_AppendAllText_Span : File_ReadWriteAllText
+ {
+ protected override bool IsAppend => true;
+
+ protected override void Write(string path, string content)
+ {
+ File.AppendAllText(path, content.AsSpan());
+ }
+
+ protected override void Write(string path, string content, Encoding encoding)
+ {
+ File.AppendAllText(path, content.AsSpan(), encoding);
+ }
+ }
+
public class File_AppendAllText_Encoded : File_AppendAllText
{
protected override void Write(string path, string content)
@@ -54,6 +69,20 @@ public void NullEncoding()
}
}
+ public class File_AppendAllText_Span_Encoded : File_AppendAllText
+ {
+ protected override void Write(string path, string content)
+ {
+ File.AppendAllText(path, content.AsSpan(), new UTF8Encoding(false));
+ }
+
+ [Fact]
+ public void NullEncoding()
+ {
+ Assert.Throws(() => File.AppendAllText(GetTestFilePath(), "Text".AsSpan(), null));
+ }
+ }
+
public class File_AppendAllLines : File_ReadWriteAllLines_Enumerable
{
protected override bool IsAppend => true;
diff --git a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/AppendAllBytes.cs b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/AppendAllBytes.cs
index 9b29f971e20dfa..da68cd7b406a2a 100644
--- a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/AppendAllBytes.cs
+++ b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/AppendAllBytes.cs
@@ -1,7 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System.IO.Tests;
using System.Linq;
using System.Text;
using Xunit;
@@ -10,13 +9,13 @@ namespace System.IO.Tests
{
public class File_AppendAllBytes : FileSystemTest
{
-
[Fact]
public void NullParameters()
{
string path = GetTestFilePath();
Assert.Throws(() => File.AppendAllBytes(null, new byte[0]));
+ Assert.Throws(() => File.AppendAllBytes(null, ReadOnlySpan.Empty));
Assert.Throws(() => File.AppendAllBytes(path, null));
}
@@ -24,12 +23,14 @@ public void NullParameters()
public void NonExistentPath()
{
Assert.Throws(() => File.AppendAllBytes(Path.Combine(TestDirectory, GetTestFileName(), GetTestFileName()), new byte[0]));
+ Assert.Throws(() => File.AppendAllBytes(Path.Combine(TestDirectory, GetTestFileName(), GetTestFileName()), ReadOnlySpan.Empty));
}
[Fact]
public void InvalidParameters()
{
Assert.Throws(() => File.AppendAllBytes(string.Empty, new byte[0]));
+ Assert.Throws(() => File.AppendAllBytes(string.Empty, ReadOnlySpan.Empty));
}
@@ -43,10 +44,11 @@ public void AppendAllBytes_WithValidInput_AppendsBytes()
File.WriteAllBytes(path, initialBytes);
File.AppendAllBytes(path, additionalBytes);
+ File.AppendAllBytes(path, additionalBytes.AsSpan());
byte[] result = File.ReadAllBytes(path);
- byte[] expectedBytes = initialBytes.Concat(additionalBytes).ToArray();
+ byte[] expectedBytes = initialBytes.Concat(additionalBytes).Concat(additionalBytes).ToArray();
Assert.True(result.SequenceEqual(expectedBytes));
}
@@ -58,6 +60,7 @@ public void EmptyContentCreatesFile()
string path = GetTestFilePath();
Assert.False(File.Exists(path));
File.AppendAllBytes(path, new byte[0]);
+ File.AppendAllBytes(path, ReadOnlySpan.Empty);
Assert.True(File.Exists(path));
Assert.Empty(File.ReadAllBytes(path));
}
@@ -71,6 +74,7 @@ public void OpenFile_ThrowsIOException()
using (File.Create(path))
{
Assert.Throws(() => File.AppendAllBytes(path, bytes));
+ Assert.Throws(() => File.AppendAllBytes(path, bytes.AsSpan()));
}
}
@@ -97,6 +101,7 @@ public void AppendToReadOnlyFileAsync()
else
{
Assert.Throws(() => File.AppendAllBytes(path, dataToAppend));
+ Assert.Throws(() => File.AppendAllBytes(path, dataToAppend.AsSpan()));
}
}
finally
diff --git a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/AppendAllBytesAsync.cs b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/AppendAllBytesAsync.cs
index 84ef880f4aa93f..89ef9b63f665de 100644
--- a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/AppendAllBytesAsync.cs
+++ b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/AppendAllBytesAsync.cs
@@ -19,6 +19,7 @@ public async Task NullParametersAsync()
string path = GetTestFilePath();
await Assert.ThrowsAsync("path", async () => await File.AppendAllBytesAsync(null, new byte[0]));
+ await Assert.ThrowsAsync("path", async () => await File.AppendAllBytesAsync(null, ReadOnlyMemory.Empty));
await Assert.ThrowsAsync("bytes", async () => await File.AppendAllBytesAsync(path, null));
}
@@ -26,12 +27,14 @@ public async Task NullParametersAsync()
public void NonExistentPathAsync()
{
Assert.ThrowsAsync(() => File.AppendAllBytesAsync(Path.Combine(TestDirectory, GetTestFileName(), GetTestFileName()), new byte[0]));
+ Assert.ThrowsAsync(() => File.AppendAllBytesAsync(Path.Combine(TestDirectory, GetTestFileName(), GetTestFileName()), ReadOnlyMemory.Empty));
}
[Fact]
public async Task InvalidParametersAsync()
{
await Assert.ThrowsAsync("path", async () => await File.AppendAllBytesAsync(string.Empty, new byte[0]));
+ await Assert.ThrowsAsync("path", async () => await File.AppendAllBytesAsync(string.Empty, ReadOnlyMemory.Empty));
}
[Fact]
@@ -44,10 +47,11 @@ public async Task AppendAllBytesAsync_WithValidInput_AppendsBytes()
await File.WriteAllBytesAsync(path, initialBytes);
await File.AppendAllBytesAsync(path, additionalBytes);
+ await File.AppendAllBytesAsync(path, additionalBytes.AsMemory());
byte[] result = await File.ReadAllBytesAsync(path);
- byte[] expectedBytes = initialBytes.Concat(additionalBytes).ToArray();
+ byte[] expectedBytes = initialBytes.Concat(additionalBytes).Concat(additionalBytes).ToArray();
Assert.True(result.SequenceEqual(expectedBytes));
}
@@ -57,6 +61,7 @@ public async Task EmptyContentCreatesFileAsync()
{
string path = GetTestFilePath();
await File.AppendAllBytesAsync(path, new byte[0]);
+ await File.AppendAllBytesAsync(path, ReadOnlyMemory.Empty);
Assert.True(File.Exists(path));
Assert.Empty(await File.ReadAllBytesAsync(path));
}
@@ -70,6 +75,7 @@ public async Task OpenFile_ThrowsIOExceptionAsync()
using (File.Create(path))
{
await Assert.ThrowsAsync(async () => await File.AppendAllBytesAsync(path, bytes));
+ await Assert.ThrowsAsync(async () => await File.AppendAllBytesAsync(path, bytes.AsMemory()));
}
}
@@ -91,11 +97,13 @@ public async Task AppendToReadOnlyFileAsync()
if (PlatformDetection.IsNotWindows && PlatformDetection.IsPrivilegedProcess)
{
await File.AppendAllBytesAsync(path, dataToAppend);
- Assert.Equal(dataToAppend, await File.ReadAllBytesAsync(path));
+ await File.AppendAllBytesAsync(path, dataToAppend.AsMemory());
+ Assert.Equal(dataToAppend.Concat(dataToAppend), await File.ReadAllBytesAsync(path));
}
else
{
await Assert.ThrowsAsync(async () => await File.AppendAllBytesAsync(path, dataToAppend));
+ await Assert.ThrowsAsync(async () => await File.AppendAllBytesAsync(path, dataToAppend.AsMemory()));
}
}
finally
diff --git a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/AppendAsync.cs b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/AppendAsync.cs
index a4be5ccdd4e950..6a7dca62bc6a98 100644
--- a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/AppendAsync.cs
+++ b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/AppendAsync.cs
@@ -28,6 +28,26 @@ public override Task TaskAlreadyCanceledAsync()
}
}
+ public class File_AppendAllTextAsync_Memory : File_ReadWriteAllTextAsync
+ {
+ protected override bool IsAppend => true;
+
+ protected override Task WriteAsync(string path, string content) => File.AppendAllTextAsync(path, content.AsMemory());
+
+ protected override Task WriteAsync(string path, string content, Encoding encoding) => File.AppendAllTextAsync(path, content.AsMemory(), encoding);
+
+ [Fact]
+ public override Task TaskAlreadyCanceledAsync()
+ {
+ string path = GetTestFilePath();
+ CancellationTokenSource source = new CancellationTokenSource();
+ CancellationToken token = source.Token;
+ source.Cancel();
+ Assert.True(File.AppendAllTextAsync(path, "".AsMemory(), token).IsCanceled);
+ return Assert.ThrowsAsync(async () => await File.AppendAllTextAsync(path, "".AsMemory(), token));
+ }
+ }
+
public class File_AppendAllTextAsync_Encoded : File_AppendAllTextAsync
{
protected override Task WriteAsync(string path, string content) =>
@@ -51,6 +71,29 @@ public override Task TaskAlreadyCanceledAsync()
}
}
+ public class File_AppendAllTextAsync_Memory_Encoded : File_AppendAllTextAsync
+ {
+ protected override Task WriteAsync(string path, string content) =>
+ File.AppendAllTextAsync(path, content.AsMemory(), new UTF8Encoding(false));
+
+ [Fact]
+ public Task NullEncodingAsync() => Assert.ThrowsAsync(
+ "encoding",
+ async () => await File.AppendAllTextAsync(GetTestFilePath(), "Text".AsMemory(), null));
+
+ [Fact]
+ public override Task TaskAlreadyCanceledAsync()
+ {
+ string path = GetTestFilePath();
+ CancellationTokenSource source = new CancellationTokenSource();
+ CancellationToken token = source.Token;
+ source.Cancel();
+ Assert.True(File.AppendAllTextAsync(path, "".AsMemory(), Encoding.UTF8, token).IsCanceled);
+ return Assert.ThrowsAsync(
+ async () => await File.AppendAllTextAsync(path, "".AsMemory(), Encoding.UTF8, token));
+ }
+ }
+
public class File_AppendAllLinesAsync : File_ReadWriteAllLines_EnumerableAsync
{
protected override bool IsAppend => true;
diff --git a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/ReadWriteAllBytes.cs b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/ReadWriteAllBytes.cs
index 0f5ecbec917824..5f56d4476d27d3 100644
--- a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/ReadWriteAllBytes.cs
+++ b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/ReadWriteAllBytes.cs
@@ -7,6 +7,7 @@
using Xunit;
using System.IO.Pipes;
using Microsoft.DotNet.XUnitExtensions;
+using System.Linq;
namespace System.IO.Tests
{
@@ -17,6 +18,7 @@ public void NullParameters()
{
string path = GetTestFilePath();
Assert.Throws(() => File.WriteAllBytes(null, new byte[0]));
+ Assert.Throws(() => File.WriteAllBytes(null, ReadOnlySpan.Empty));
Assert.Throws(() => File.WriteAllBytes(path, null));
Assert.Throws(() => File.ReadAllBytes(null));
}
@@ -25,6 +27,7 @@ public void NullParameters()
public void InvalidParameters()
{
Assert.Throws(() => File.WriteAllBytes(string.Empty, new byte[0]));
+ Assert.Throws(() => File.WriteAllBytes(string.Empty, ReadOnlySpan.Empty));
Assert.Throws(() => File.ReadAllBytes(string.Empty));
}
@@ -40,6 +43,7 @@ public void EmptyContentCreatesFile()
{
string path = GetTestFilePath();
File.WriteAllBytes(path, new byte[0]);
+ File.WriteAllBytes(path, ReadOnlySpan.Empty);
Assert.True(File.Exists(path));
Assert.Empty(File.ReadAllText(path));
File.Delete(path);
@@ -54,17 +58,28 @@ public void ValidWrite(int size)
byte[] buffer = Encoding.UTF8.GetBytes(new string('c', size));
File.WriteAllBytes(path, buffer);
Assert.Equal(buffer, File.ReadAllBytes(path));
+ File.WriteAllBytes(path, buffer.AsSpan());
+ Assert.Equal(buffer, File.ReadAllBytes(path));
File.Delete(path);
}
- [Fact]
- public void Overwrite()
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public void Overwrite(bool useSpan)
{
string path = GetTestFilePath();
byte[] bytes = Encoding.UTF8.GetBytes(new string('c', 100));
byte[] overwriteBytes = Encoding.UTF8.GetBytes(new string('b', 50));
File.WriteAllBytes(path, bytes);
- File.WriteAllBytes(path, overwriteBytes);
+ if (useSpan)
+ {
+ File.WriteAllBytes(path, overwriteBytes.AsSpan());
+ }
+ else
+ {
+ File.WriteAllBytes(path, overwriteBytes);
+ }
Assert.Equal(overwriteBytes, File.ReadAllBytes(path));
}
@@ -76,6 +91,7 @@ public void OpenFile_ThrowsIOException()
using (File.Create(path))
{
Assert.Throws(() => File.WriteAllBytes(path, bytes));
+ Assert.Throws(() => File.WriteAllBytes(path, bytes.AsSpan()));
Assert.Throws(() => File.ReadAllBytes(path));
}
}
@@ -96,10 +112,14 @@ public void WriteToReadOnlyFile()
if (PlatformDetection.IsNotWindows && PlatformDetection.IsPrivilegedProcess)
{
File.WriteAllBytes(path, "text"u8.ToArray());
- Assert.Equal("text"u8.ToArray(), File.ReadAllBytes(path));
+ File.WriteAllBytes(path, "text"u8);
+ Assert.Equal("texttext"u8.ToArray(), File.ReadAllBytes(path));
}
else
+ {
Assert.Throws(() => File.WriteAllBytes(path, "text"u8.ToArray()));
+ Assert.Throws(() => File.WriteAllBytes(path, "text"u8));
+ }
}
finally
{
diff --git a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/ReadWriteAllBytesAsync.cs b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/ReadWriteAllBytesAsync.cs
index 62772f2ee1e862..662e4aa109100e 100644
--- a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/ReadWriteAllBytesAsync.cs
+++ b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/ReadWriteAllBytesAsync.cs
@@ -6,6 +6,7 @@
using System.Threading.Tasks;
using Xunit;
using System.IO.Pipes;
+using System.Linq;
namespace System.IO.Tests
{
@@ -16,6 +17,7 @@ public async Task NullParametersAsync()
{
string path = GetTestFilePath();
await Assert.ThrowsAsync("path", async () => await File.WriteAllBytesAsync(null, new byte[0]));
+ await Assert.ThrowsAsync("path", async () => await File.WriteAllBytesAsync(null, ReadOnlyMemory.Empty));
await Assert.ThrowsAsync("bytes", async () => await File.WriteAllBytesAsync(path, null));
await Assert.ThrowsAsync("path", async () => await File.ReadAllBytesAsync(null));
}
@@ -24,6 +26,7 @@ public async Task NullParametersAsync()
public async Task InvalidParametersAsync()
{
await Assert.ThrowsAsync("path", async () => await File.WriteAllBytesAsync(string.Empty, new byte[0]));
+ await Assert.ThrowsAsync("path", async () => await File.WriteAllBytesAsync(string.Empty, ReadOnlyMemory.Empty));
await Assert.ThrowsAsync("path", async () => await File.ReadAllBytesAsync(string.Empty));
}
@@ -39,6 +42,7 @@ public async Task EmptyContentCreatesFileAsync()
{
string path = GetTestFilePath();
await File.WriteAllBytesAsync(path, new byte[0]);
+ await File.WriteAllBytesAsync(path, ReadOnlyMemory.Empty);
Assert.True(File.Exists(path));
Assert.Empty(await File.ReadAllTextAsync(path));
File.Delete(path);
@@ -53,29 +57,41 @@ public async Task ValidWriteAsync(int size)
byte[] buffer = Encoding.UTF8.GetBytes(new string('c', size));
await File.WriteAllBytesAsync(path, buffer);
Assert.Equal(buffer, await File.ReadAllBytesAsync(path));
+ await File.WriteAllBytesAsync(path, buffer.AsMemory());
+ Assert.Equal(buffer, await File.ReadAllBytesAsync(path));
File.Delete(path);
}
[Fact]
- public Task AlreadyCanceledAsync()
+ public async Task AlreadyCanceledAsync()
{
string path = GetTestFilePath();
CancellationTokenSource source = new CancellationTokenSource();
CancellationToken token = source.Token;
source.Cancel();
Assert.True(File.WriteAllBytesAsync(path, new byte[0], token).IsCanceled);
- return Assert.ThrowsAsync(
- async () => await File.WriteAllBytesAsync(path, new byte[0], token));
+ Assert.True(File.WriteAllBytesAsync(path, ReadOnlyMemory.Empty, token).IsCanceled);
+ await Assert.ThrowsAsync(async () => await File.WriteAllBytesAsync(path, new byte[0], token));
+ await Assert.ThrowsAsync(async () => await File.WriteAllBytesAsync(path, ReadOnlyMemory.Empty, token));
}
- [Fact]
- public async Task OverwriteAsync()
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task OverwriteAsync(bool useMemory)
{
string path = GetTestFilePath();
byte[] bytes = Encoding.UTF8.GetBytes(new string('c', 100));
byte[] overwriteBytes = Encoding.UTF8.GetBytes(new string('b', 50));
await File.WriteAllBytesAsync(path, bytes);
- await File.WriteAllBytesAsync(path, overwriteBytes);
+ if (useMemory)
+ {
+ await File.WriteAllBytesAsync(path, overwriteBytes);
+ }
+ else
+ {
+ await File.WriteAllBytesAsync(path, overwriteBytes);
+ }
Assert.Equal(overwriteBytes, await File.ReadAllBytesAsync(path));
}
@@ -87,6 +103,7 @@ public async Task OpenFile_ThrowsIOExceptionAsync()
using (File.Create(path))
{
await Assert.ThrowsAsync(async () => await File.WriteAllBytesAsync(path, bytes));
+ await Assert.ThrowsAsync(async () => await File.WriteAllBytesAsync(path, bytes.AsMemory()));
await Assert.ThrowsAsync(async () => await File.ReadAllBytesAsync(path));
}
}
@@ -107,10 +124,14 @@ public async Task WriteToReadOnlyFileAsync()
if (PlatformDetection.IsNotWindows && PlatformDetection.IsPrivilegedProcess)
{
await File.WriteAllBytesAsync(path, "text"u8.ToArray());
- Assert.Equal("text"u8.ToArray(), await File.ReadAllBytesAsync(path));
+ await File.WriteAllBytesAsync(path, "text"u8.ToArray().AsMemory());
+ Assert.Equal("texttext"u8.ToArray(), await File.ReadAllBytesAsync(path));
}
else
+ {
await Assert.ThrowsAsync(async () => await File.WriteAllBytesAsync(path, "text"u8.ToArray()));
+ await Assert.ThrowsAsync(async () => await File.WriteAllBytesAsync(path, "text"u8.ToArray().AsMemory()));
+ }
}
finally
{
diff --git a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/ReadWriteAllText.cs b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/ReadWriteAllText.cs
index 749877010e6c1d..e22512ed059acd 100644
--- a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/ReadWriteAllText.cs
+++ b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/ReadWriteAllText.cs
@@ -225,4 +225,25 @@ public void NullEncoding()
Assert.Throws(() => File.ReadAllText(path, null));
}
}
+
+ public class File_ReadWriteAllText_Span_Encoded : File_ReadWriteAllText
+ {
+ protected override void Write(string path, string content)
+ {
+ File.WriteAllText(path, content.AsSpan(), new UTF8Encoding(false));
+ }
+
+ protected override string Read(string path)
+ {
+ return File.ReadAllText(path, new UTF8Encoding(false));
+ }
+
+ [Fact]
+ public void NullEncoding()
+ {
+ string path = GetTestFilePath();
+ Assert.Throws(() => File.WriteAllText(path, "Text".AsSpan(), null));
+ Assert.Throws(() => File.ReadAllText(path, null));
+ }
+ }
}
diff --git a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/ReadWriteAllTextAsync.cs b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/ReadWriteAllTextAsync.cs
index 09825f49f5c260..723ed95aa5da7f 100644
--- a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/ReadWriteAllTextAsync.cs
+++ b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/File/ReadWriteAllTextAsync.cs
@@ -224,4 +224,35 @@ public override Task TaskAlreadyCanceledAsync()
async () => await File.WriteAllTextAsync(path, "", Encoding.UTF8, token));
}
}
+
+ public class File_ReadWriteAllText_Memory_EncodedAsync : File_ReadWriteAllTextAsync
+ {
+ protected override Task WriteAsync(string path, string content) =>
+ File.WriteAllTextAsync(path, content.AsMemory(), new UTF8Encoding(false));
+
+ protected override Task ReadAsync(string path) =>
+ File.ReadAllTextAsync(path, new UTF8Encoding(false));
+
+ [Fact]
+ public async Task NullEncodingAsync()
+ {
+ string path = GetTestFilePath();
+ await Assert.ThrowsAsync("encoding", async () => await File.WriteAllTextAsync(path, "Text", null));
+ await Assert.ThrowsAsync("encoding", async () => await File.WriteAllTextAsync(path, "Text".AsMemory(), null));
+ await Assert.ThrowsAsync("encoding", async () => await File.ReadAllTextAsync(path, null));
+ }
+
+ [Fact]
+ public override async Task TaskAlreadyCanceledAsync()
+ {
+ string path = GetTestFilePath();
+ CancellationTokenSource source = new CancellationTokenSource();
+ CancellationToken token = source.Token;
+ source.Cancel();
+ Assert.True(File.WriteAllTextAsync(path, "", Encoding.UTF8, token).IsCanceled);
+ Assert.True(File.WriteAllTextAsync(path, "".AsMemory(), Encoding.UTF8, token).IsCanceled);
+ await Assert.ThrowsAsync(async () => await File.WriteAllTextAsync(path, "", Encoding.UTF8, token));
+ await Assert.ThrowsAsync(async () => await File.WriteAllTextAsync(path, "".AsMemory(), Encoding.UTF8, token));
+ }
+ }
}