C# EndOfStreamException
last modified April 20, 2025
This tutorial explains how to handle the EndOfStreamException in C# when working with streams. This exception occurs when trying to read past the end of a stream.
The EndOfStreamException is thrown when reading is attempted past the end of a stream. It's commonly encountered with BinaryReader, StreamReader, and other stream-based classes.
EndOfStreamException
indicates that the underlying stream has
reached its end. Proper handling prevents crashes when processing streams of
unknown length.
Basic EndOfStreamException Example
This example demonstrates how EndOfStreamException occurs when reading past the end of a file using BinaryReader.
using System; using System.IO; class Program { static void Main() { try { using (var stream = new MemoryStream(new byte[4])) using (var reader = new BinaryReader(stream)) { // Read one int (4 bytes) - OK int value1 = reader.ReadInt32(); Console.WriteLine($"First read: {value1}"); // Attempt to read another int - throws EndOfStreamException int value2 = reader.ReadInt32(); Console.WriteLine($"Second read: {value2}"); } } catch (EndOfStreamException ex) { Console.WriteLine($"Error: {ex.Message}"); Console.WriteLine("Attempted to read past end of stream"); } } }
The code creates a MemoryStream with 4 bytes (enough for one int). After reading one integer, attempting to read another throws EndOfStreamException. The example shows the basic scenario where this exception occurs - when trying to read more data than exists in the stream.
The BinaryReader successfully reads the first 4-byte integer, but the second read attempt fails because the stream has no more data. The exception is caught and handled gracefully with an informative message. This demonstrates the importance of checking stream position or handling this exception when reading streams.
Checking Stream Position
This example shows how to avoid EndOfStreamException by checking the stream position before reading.
using System; using System.IO; class Program { static void Main() { using (var stream = new MemoryStream(new byte[8])) using (var reader = new BinaryReader(stream)) { while (reader.BaseStream.Position < reader.BaseStream.Length) { int value = reader.ReadInt32(); Console.WriteLine($"Read value: {value}"); } Console.WriteLine("Reached end of stream successfully"); } } }
By comparing Position and Length properties, we can read exactly until the end without exceptions. This is a proactive approach to stream reading. The example uses a MemoryStream with 8 bytes (enough for two integers). The while loop continues reading as long as the current position hasn't reached the stream's end.
This method is more efficient than catching exceptions and is preferred when the stream structure is known. It demonstrates good practice for reading streams where you control the reading process and can check position before each read operation.
Reading Variable-Length Data
This example handles EndOfStreamException when reading variable-length data from a file.
using System; using System.IO; class Program { static void Main() { string filePath = "data.bin"; try { using (var stream = File.OpenRead(filePath)) using (var reader = new BinaryReader(stream)) { while (true) { try { int id = reader.ReadInt32(); string name = reader.ReadString(); Console.WriteLine($"ID: {id}, Name: {name}"); } catch (EndOfStreamException) { Console.WriteLine("Finished reading file"); break; } } } } catch (FileNotFoundException) { Console.WriteLine($"File not found: {filePath}"); } } }
The code attempts to read records until EndOfStreamException occurs, which serves as the termination condition. This pattern is useful when the exact number of records isn't known in advance. The example shows a common scenario where a binary file contains multiple records, each consisting of an integer ID followed by a string.
The inner try-catch block catches EndOfStreamException to gracefully exit the reading loop when the file ends. This approach is particularly useful when processing files where the record count isn't stored separately, or when working with legacy file formats that don't include record count metadata.
Custom Stream Wrapper
This example demonstrates creating a custom stream wrapper that provides safe reading methods with explicit end-of-stream checks.
using System; using System.IO; public class SafeBinaryReader : BinaryReader { public SafeBinaryReader(Stream input) : base(input) { } public bool TryReadInt32(out int value) { value = 0; if (BaseStream.Position + 4 > BaseStream.Length) return false; value = ReadInt32(); return true; } public bool TryReadString(out string value) { value = null; try { value = ReadString(); return true; } catch (EndOfStreamException) { return false; } } } class Program { static void Main() { byte[] data = new byte[10]; new Random().NextBytes(data); using (var stream = new MemoryStream(data)) using (var reader = new SafeBinaryReader(stream)) { while (reader.TryReadInt32(out int value)) { Console.WriteLine($"Read integer: {value}"); } Console.WriteLine("No more integers to read"); } } }
The SafeBinaryReader class extends BinaryReader with TryRead methods that return false instead of throwing exceptions. This provides cleaner control flow. The example shows how to create a more user-friendly wrapper around BinaryReader that avoids exceptions for expected conditions like end-of-stream.
The TryReadInt32 method checks if enough bytes remain before reading, while TryReadString catches the EndOfStreamException internally. This pattern is useful when you want to provide explicit end-of-stream detection without forcing callers to use exception handling for normal control flow. It demonstrates how to create more robust stream handling components.
Network Stream Handling
This example shows EndOfStreamException handling when reading from a NetworkStream, where the stream might close unexpectedly.
using System; using System.IO; using System.Net.Sockets; class Program { static void Main() { try { using (var client = new TcpClient("example.com", 80)) using (var stream = client.GetStream()) using (var reader = new BinaryReader(stream)) { // Simulate reading response (in real code, follow protocol) while (true) { try { byte[] data = reader.ReadBytes(1024); if (data.Length == 0) break; Console.WriteLine($"Read {data.Length} bytes"); } catch (EndOfStreamException) { Console.WriteLine("Connection closed by remote host"); break; } } } } catch (SocketException ex) { Console.WriteLine($"Network error: {ex.Message}"); } } }
Network streams can close unexpectedly, making EndOfStreamException handling essential for robust network code. This example demonstrates reading from a TCP connection to a web server. The while loop attempts to read data in 1KB chunks until either an empty read (indicating graceful closure) or an EndOfStreamException occurs (indicating abrupt closure).
The example shows proper handling of both the expected end-of-stream condition and network errors. In real applications, you would typically follow a specific protocol rather than just reading until the stream ends. This pattern is particularly important for network programming where connections might be terminated unexpectedly.
Reading Partial Data
This example demonstrates how to handle partial reads when EndOfStreamException occurs mid-record.
using System; using System.IO; class Program { static void ReadData(BinaryReader reader) { try { int id = reader.ReadInt32(); string name = reader.ReadString(); DateTime timestamp = new DateTime(reader.ReadInt64()); Console.WriteLine($"Complete record: {id}, {name}, {timestamp}"); } catch (EndOfStreamException) { Console.WriteLine("Warning: Incomplete record at end of file"); // Log or handle partial data } } static void Main() { // Create test file with partial record using (var stream = new MemoryStream()) { using (var writer = new BinaryWriter(stream)) { writer.Write(1); writer.Write("Complete Record"); writer.Write(DateTime.Now.Ticks); // Partial record writer.Write(2); writer.Write("Partial"); // Missing timestamp } stream.Position = 0; using (var reader = new BinaryReader(stream)) { ReadData(reader); // Reads complete record ReadData(reader); // Attempts to read partial record } } } }
When reading complex records, EndOfStreamException might occur mid-record. This example shows how to detect and handle such cases. The code defines a method that reads a record consisting of an integer, string, and DateTime. When a partial record exists at the end of the file, the EndOfStreamException is caught and handled.
The example creates a test stream with one complete record and one partial record (missing the timestamp). This demonstrates how to gracefully handle corrupted or truncated files where records might be incomplete. In production code, you might log such incidents or attempt recovery depending on your requirements.
Combining with Other Exceptions
This example shows comprehensive exception handling when reading from files, including EndOfStreamException.
using System; using System.IO; class Program { static void ProcessFile(string path) { try { using (var stream = File.Open(path, FileMode.Open)) using (var reader = new BinaryReader(stream)) { while (reader.BaseStream.Position < reader.BaseStream.Length) { try { int id = reader.ReadInt32(); double value = reader.ReadDouble(); Console.WriteLine($"Record: {id}, {value}"); } catch (EndOfStreamException) { Console.WriteLine("Unexpected end of file"); break; } catch (IOException ex) { Console.WriteLine($"I/O error: {ex.Message}"); break; } } } } catch (FileNotFoundException) { Console.WriteLine($"File not found: {path}"); } catch (UnauthorizedAccessException) { Console.WriteLine($"Access denied: {path}"); } } static void Main() { ProcessFile("data.bin"); } }
The example demonstrates a complete file processing method with multiple exception handlers. EndOfStreamException is caught separately from other I/O errors for specific handling. The outer try-catch handles file access issues, while the inner one handles stream reading errors.
This structure allows different responses to different error conditions - file not found vs. read errors vs. unexpected end of file. The example shows best practices for robust file handling in C#, where different exceptions require different handling strategies. The code maintains readability while providing comprehensive error handling.
Source
EndOfStreamException Class Documentation
This tutorial covered handling the EndOfStreamException in C# when working with streams, including prevention, detection, and recovery techniques.
Author
List all C# tutorials.