Return StreamReader to Beginning
Categories:
Mastering StreamReader: Returning to the Beginning of a Stream

Learn how to efficiently reset a StreamReader's position to the beginning of its underlying stream in C# for reprocessing or re-reading data.
When working with StreamReader in C#, you often need to process the contents of a stream multiple times. A common scenario is reading a file, performing some initial validation, and then needing to re-read it from the start for detailed parsing. Unlike a simple Stream, StreamReader adds buffering and character encoding logic, which complicates directly manipulating the underlying stream's position. This article will guide you through the correct and efficient ways to return a StreamReader to its beginning.
Understanding StreamReader and Stream Positions
A StreamReader wraps an underlying Stream (like a FileStream or MemoryStream) and provides methods for reading characters and lines, handling character encodings automatically. While the underlying Stream has a Position property that can be set, directly manipulating this property when a StreamReader is active can lead to unexpected behavior due to the StreamReader's internal buffer. The StreamReader caches data from the stream to optimize read operations, and simply resetting the stream's position won't clear this internal buffer.

StreamReader's internal buffering mechanism
Method 1: Resetting the Underlying Stream's Position
The most direct way to return to the beginning is to reset the position of the StreamReader's underlying stream. However, this requires an additional step: clearing the StreamReader's internal buffer. This method is suitable when the underlying stream supports seeking (i.e., its CanSeek property is true).
using System;
using System.IO;
using System.Text;
public class StreamReaderResetExample
{
public static void Main(string[] args)
{
string data = "Line 1\nLine 2\nLine 3";
using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(data)))
{
using (StreamReader reader = new StreamReader(ms, Encoding.UTF8))
{
Console.WriteLine("--- First Read ---");
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
// Check if the stream can seek
if (ms.CanSeek)
{
Console.WriteLine("\n--- Resetting and Second Read ---");
ms.Position = 0; // Reset the underlying stream's position
reader.DiscardBufferedData(); // Crucial: Clear StreamReader's internal buffer
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
else
{
Console.WriteLine("\nUnderlying stream does not support seeking.");
}
}
}
}
}
stream.CanSeek before attempting to set stream.Position. If CanSeek is false, attempting to set the position will result in a NotSupportedException.Method 2: Recreating the StreamReader
If the underlying stream does not support seeking (e.g., a network stream or a stream from a non-seekable source), or if you prefer a simpler, more robust approach that avoids potential buffering issues, you can recreate the StreamReader instance. This assumes you still have access to the original stream or can obtain a new stream instance pointing to the same data source.
using System;
using System.IO;
using System.Text;
public class RecreateStreamReaderExample
{
public static void Main(string[] args)
{
string data = "Alpha\nBeta\nGamma";
// For demonstration, we'll use a MemoryStream, but imagine this is a non-seekable stream
// or a new stream from the same file path.
MemoryStream originalStream = new MemoryStream(Encoding.UTF8.GetBytes(data));
// First StreamReader instance
using (StreamReader reader1 = new StreamReader(originalStream, Encoding.UTF8))
{
Console.WriteLine("--- First Read (Reader 1) ---");
string line;
while ((line = reader1.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
// To re-read, we need to reset the original stream's position
// and then create a *new* StreamReader instance.
// Note: If originalStream was truly non-seekable, you'd need to get a new stream source.
originalStream.Position = 0;
// Second StreamReader instance
using (StreamReader reader2 = new StreamReader(originalStream, Encoding.UTF8))
{
Console.WriteLine("\n--- Second Read (Reader 2) ---");
string line;
while ((line = reader2.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
originalStream.Dispose(); // Dispose the underlying stream
}
}
StreamReader, ensure the underlying stream's position is reset before creating the new StreamReader instance. If you are reading from a file, simply creating a new FileStream and StreamReader for the same file path will achieve this.Choosing the Right Approach
The best approach depends on your specific scenario:
Use
stream.Position = 0;andreader.DiscardBufferedData();when:- The underlying stream (
StreamReader.BaseStream) supports seeking (CanSeekistrue). - You want to avoid the overhead of creating a new
StreamReaderobject. - You are confident in managing the stream's position and the reader's buffer.
- The underlying stream (
Recreate the
StreamReaderwhen:- The underlying stream does not support seeking (
CanSeekisfalse). - You are reading from a file and it's simpler to just open the file again.
- You want to ensure a completely fresh state for the
StreamReader, avoiding any potential lingering buffer issues from previous reads. - The performance difference of creating a new
StreamReaderis negligible for your application.
- The underlying stream does not support seeking (

Decision workflow for resetting a StreamReader