diff --git a/src/process.tests/PipingTests.cs b/src/process.tests/PipingTests.cs
index a184743..82f23b3 100644
--- a/src/process.tests/PipingTests.cs
+++ b/src/process.tests/PipingTests.cs
@@ -64,6 +64,42 @@ internal sealed class PipingTests
await Assert.That(result.StandardOutput.Trim()).IsEqualTo("Hello World!");
}
+ [Test]
+ public async Task I_can_execute_a_command_and_pipe_the_stdin_from_a_stream_with_a_custom_buffer_size()
+ {
+ // Arrange
+ using var source = new MemoryStream("Hello World!"u8.ToArray());
+
+ var cmd = PipeSource.FromStream(source, 1) |
+ new Command(Testing.Fixture.Program.FilePath)
+ .WithArguments("echo-stdin");
+
+ // Act
+ var result = await cmd.ExecuteBufferedAsync();
+
+ // Assert
+ await Assert.That(result.StandardOutput.Trim()).IsEqualTo("Hello World!");
+ }
+
+ [Test]
+ public async Task I_can_execute_a_command_and_pipe_the_stdin_from_a_file_with_a_custom_buffer_size()
+ {
+ // Arrange
+ using var dir = TestTempDirectory.Create();
+ var filePath = Path.Combine(dir.Path, "input.txt");
+ await File.WriteAllTextAsync(filePath, "Hello World!");
+
+ var cmd = PipeSource.FromFile(filePath, 1) |
+ new Command(Testing.Fixture.Program.FilePath)
+ .WithArguments("echo-stdin");
+
+ // Act
+ var result = await cmd.ExecuteBufferedAsync();
+
+ // Assert
+ await Assert.That(result.StandardOutput.Trim()).IsEqualTo("Hello World!");
+ }
+
[Test]
public async Task I_can_execute_a_command_and_pipe_the_stdin_from_memory()
{
@@ -220,6 +256,43 @@ internal sealed class PipingTests
await Assert.That(stream.Length).IsEqualTo(100_000);
}
+ [Test]
+ public async Task I_can_execute_a_command_and_pipe_the_stdout_into_a_stream_with_a_custom_buffer_size()
+ {
+ // Arrange
+ using var stream = new MemoryStream();
+ var target = PipeTarget.ToStream(stream, 1);
+
+ var cmd = new Command(Testing.Fixture.Program.FilePath)
+ .WithArguments(["generate", "blob", "--length", "100000"]) |
+ target;
+
+ // Act
+ await cmd.ExecuteAsync();
+
+ // Assert
+ await Assert.That(stream.Length).IsEqualTo(100_000);
+ }
+
+ [Test]
+ public async Task I_can_execute_a_command_and_pipe_the_stdout_into_a_file_with_a_custom_buffer_size()
+ {
+ // Arrange
+ using var dir = TestTempDirectory.Create();
+ var filePath = Path.Combine(dir.Path, "output.bin");
+ var target = PipeTarget.ToFile(filePath, 1);
+
+ var cmd = new Command(Testing.Fixture.Program.FilePath)
+ .WithArguments(["generate", "blob", "--length", "100000"]) |
+ target;
+
+ // Act
+ await cmd.ExecuteAsync();
+
+ // Assert
+ await Assert.That(new FileInfo(filePath).Length).IsEqualTo(100_000);
+ }
+
[Test]
public async Task I_can_execute_a_command_and_pipe_the_stdout_into_a_string_builder()
{
diff --git a/src/process/PipeSource.cs b/src/process/PipeSource.cs
index ed221c5..4f00157 100644
--- a/src/process/PipeSource.cs
+++ b/src/process/PipeSource.cs
@@ -67,6 +67,14 @@ public abstract partial class PipeSource
return Create(stream.CopyToAsync);
}
+ ///
+ /// Creates a pipe source that reads from the specified stream.
+ ///
+ public static PipeSource FromStream(Stream stream, int bufferSize)
+ {
+ return Create((target, token) => stream.CopyToAsync(target, bufferSize, token));
+ }
+
///
/// Creates a pipe source that reads from the specified file.
///
@@ -79,6 +87,18 @@ public abstract partial class PipeSource
});
}
+ ///
+ /// Creates a pipe source that reads from the specified file.
+ ///
+ public static PipeSource FromFile(string filePath, int bufferSize)
+ {
+ return Create(async (destination, cancellationToken) =>
+ {
+ await using var source = File.OpenRead(filePath);
+ await source.CopyToAsync(destination, bufferSize, cancellationToken);
+ });
+ }
+
///
/// Creates a pipe source that reads from the specified memory buffer.
///
@@ -89,11 +109,12 @@ public abstract partial class PipeSource
}
///
- /// Creates a pipe source that reads from the specified byte array.
+ /// Creates a pipe source that reads from the specified string.
+ /// Uses for encoding.
///
- public static PipeSource FromBytes(byte[] data)
+ public static PipeSource FromString(string str)
{
- return FromBytes((ReadOnlyMemory)data);
+ return FromString(str, Console.InputEncoding);
}
///
@@ -104,15 +125,6 @@ public abstract partial class PipeSource
return FromBytes(encoding.GetBytes(str));
}
- ///
- /// Creates a pipe source that reads from the specified string.
- /// Uses for encoding.
- ///
- public static PipeSource FromString(string str)
- {
- return FromString(str, Console.InputEncoding);
- }
-
///
/// Creates a pipe source that reads from the standard output of the specified command.
///
diff --git a/src/process/PipeTarget.cs b/src/process/PipeTarget.cs
index f9cc99f..fbc1c97 100644
--- a/src/process/PipeTarget.cs
+++ b/src/process/PipeTarget.cs
@@ -155,6 +155,17 @@ public partial class PipeTarget
await origin.CopyToAsync(stream, cancellationToken));
}
+ ///
+ /// Creates a pipe target that writes to the specified stream.
+ ///
+ /// The stream to which the contents of the source will be copied.
+ /// The size, in bytes, of the buffer. This value must be greater than zero. The default size is 81920.
+ public static PipeTarget ToStream(Stream stream, int bufferSize)
+ {
+ return Create(async (origin, cancellationToken) =>
+ await origin.CopyToAsync(stream, bufferSize, cancellationToken));
+ }
+
///
/// Creates a pipe target that writes to the specified file.
///
@@ -162,11 +173,48 @@ public partial class PipeTarget
{
return Create(async (origin, cancellationToken) =>
{
- await using var target = File.Create(filePath);
+ var options = new FileStreamOptions
+ {
+ Access = FileAccess.Write,
+ Mode = FileMode.Create,
+ Share = FileShare.Read,
+ Options = FileOptions.Asynchronous
+ };
+ await using var target = new FileStream(filePath, options);
await origin.CopyToAsync(target, cancellationToken);
});
}
+ ///
+ /// Creates a pipe target that writes to the specified file.
+ ///
+ /// The path and name of the file to create and write the content to.
+ /// The size, in bytes, of the buffer. This value must be greater than zero. The default size is 81920.
+ public static PipeTarget ToFile(string filePath, int bufferSize)
+ {
+ return Create(async (origin, cancellationToken) =>
+ {
+ var options = new FileStreamOptions
+ {
+ Access = FileAccess.Write,
+ Mode = FileMode.Create,
+ Share = FileShare.Read,
+ Options = FileOptions.Asynchronous
+ };
+ await using var target = new FileStream(filePath, options);
+ await origin.CopyToAsync(target, bufferSize, cancellationToken);
+ });
+ }
+
+ ///
+ /// Creates a pipe target that writes to the specified string builder.
+ /// Uses for decoding.
+ ///
+ public static PipeTarget ToStringBuilder(StringBuilder stringBuilder)
+ {
+ return ToStringBuilder(stringBuilder, Console.OutputEncoding);
+ }
+
///
/// Creates a pipe target that writes to the specified string builder.
///
@@ -191,12 +239,12 @@ public partial class PipeTarget
}
///
- /// Creates a pipe target that writes to the specified string builder.
+ /// Creates a pipe target that invokes the specified asynchronous delegate on every line written to the stream.
/// Uses for decoding.
///
- public static PipeTarget ToStringBuilder(StringBuilder stringBuilder)
+ public static PipeTarget ToDelegate(Func func)
{
- return ToStringBuilder(stringBuilder, Console.OutputEncoding);
+ return ToDelegate(func, Console.OutputEncoding);
}
///
@@ -218,7 +266,7 @@ public partial class PipeTarget
/// Creates a pipe target that invokes the specified asynchronous delegate on every line written to the stream.
/// Uses for decoding.
///
- public static PipeTarget ToDelegate(Func func)
+ public static PipeTarget ToDelegate(Func func)
{
return ToDelegate(func, Console.OutputEncoding);
}
@@ -232,12 +280,12 @@ public partial class PipeTarget
}
///
- /// Creates a pipe target that invokes the specified asynchronous delegate on every line written to the stream.
+ /// Creates a pipe target that invokes the specified synchronous delegate on every line written to the stream.
/// Uses for decoding.
///
- public static PipeTarget ToDelegate(Func func)
+ public static PipeTarget ToDelegate(Action action)
{
- return ToDelegate(func, Console.OutputEncoding);
+ return ToDelegate(action, Console.OutputEncoding);
}
///
@@ -253,15 +301,6 @@ public partial class PipeTarget
}, encoding);
}
- ///
- /// Creates a pipe target that invokes the specified synchronous delegate on every line written to the stream.
- /// Uses for decoding.
- ///
- public static PipeTarget ToDelegate(Action action)
- {
- return ToDelegate(action, Console.OutputEncoding);
- }
-
///
/// Creates a pipe target that replicates data over multiple inner targets.
///