A Stream provides byte-oriented input or output across sources such as files, HTTP response bodies, memory, and console I/O. Depending on the task, wrap it in a StreamReader for line-by-line text or pass it directly to a parser such as JsonDocument. section 4.2.1 section 7.2
A practical file-processing flow can:
- Open an input file with OpenRead, which returns a read-only stream. section 4.2.1
- Choose an output stream: open a file or write to standard console output. Existing files may need to be deleted first; OpenWrite can leave old trailing content if new content is shorter. section 4.2.1
- Parse JSON from the input stream and write results through a StreamWriter. section 4.2.1
Methods that accept Stream can work with files, network data, memory, or custom implementations. That flexibility also makes stream-based code easier to test without depending on a real file. section 7.2 section 7.2.1
Listing 7.7 Searching a Stream line by line for matching text
public static class Utils
{
public static string? FindFirstMatchingLine(
Stream stream, string searchText)
{
var reader = new StreamReader(stream); #1
string? line;
while ((line = reader.ReadLine()) != null)
{
if (line.Contains(searchText, #2
StringComparison.OrdinalIgnoreCase))
{
return line;
}
}
return null;
}
}
A line-search method reads from a Stream through StreamReader, illustrating a reusable stream-based operation. section 7.2
Listing 7.8 A unit test for FindFirstMatchingLine that uses a MemoryStream
[Fact]
public void MemoryStream()
{
using MemoryStream stream = new(); #1
StreamWriter writer = new(stream);
writer.WriteLine("abc"); #2
writer.WriteLine("def");
writer.WriteLine("ghi");
writer.Flush(); #3
stream.Seek(0, SeekOrigin.Begin); #4
var line = Utils.FindFirstMatchingLine(stream, "f"); #5
Assert.Equal("def", line);
}
A MemoryStream supplies test input without requiring a file. section 7.2.1


















