C# StreamReader and StreamWriter
Introduction
File handling is an essential skill in programming. In C#, the StreamReader
and StreamWriter
classes provide a convenient way to read from and write to text files. These classes are part of the System.IO
namespace and offer efficient methods for handling text-based data.
In this tutorial, you'll learn:
- What
StreamReader
andStreamWriter
are - How to read text from files line by line or all at once
- How to write text to files
- Best practices for file handling
- Real-world applications
Understanding StreamReader and StreamWriter
What are Streams?
In C#, a stream is an abstraction that represents a flow of data between a source and a destination. Streams are used to read from and write to various data sources such as files, memory, and network connections.
StreamReader
StreamReader
is a class that reads characters from a byte stream in a particular encoding. It's specifically designed for reading characters from files, making it ideal for text file operations.
StreamWriter
StreamWriter
is a class that writes characters to a file in a specific encoding. It's used to create new text files or append to existing ones.
Reading Text Files with StreamReader
Basic Usage
To read from a text file using StreamReader
, follow these steps:
using System;
using System.IO;
class Program
{
static void Main()
{
string filePath = "example.txt";
try
{
// Create an instance of StreamReader to read from a file
using (StreamReader reader = new StreamReader(filePath))
{
// Read the entire file content at once
string content = reader.ReadToEnd();
Console.WriteLine("File content:");
Console.WriteLine(content);
} // The StreamReader is automatically closed when the using block ends
}
catch (FileNotFoundException)
{
Console.WriteLine($"File not found: {filePath}");
}
catch (IOException ex)
{
Console.WriteLine($"An error occurred while reading the file: {ex.Message}");
}
}
}
Let's assume the file "example.txt" contains:
Hello, world!
This is a sample text file.
Welcome to C# file handling.
The output would be:
File content:
Hello, world!
This is a sample text file.
Welcome to C# file handling.
Reading Line by Line
Often, you'll want to process a file line by line, especially for large files:
using System;
using System.IO;
class Program
{
static void Main()
{
string filePath = "example.txt";
try
{
using (StreamReader reader = new StreamReader(filePath))
{
string line;
int lineNumber = 1;
// Read and display each line until the end of file
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine($"Line {lineNumber}: {line}");
lineNumber++;
}
}
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred: {ex.Message}");
}
}
}
Output:
Line 1: Hello, world!
Line 2: This is a sample text file.
Line 3: Welcome to C# file handling.
Useful StreamReader Methods
Here are some commonly used methods of the StreamReader
class:
ReadToEnd()
: Reads all characters from the current position to the end of the fileReadLine()
: Reads a line of characters from the current stream and returns it as a stringRead()
: Reads the next character from the input streamPeek()
: Returns the next available character without actually reading it
Writing Text Files with StreamWriter
Basic Usage
To write to a text file using StreamWriter
:
using System;
using System.IO;
class Program
{
static void Main()
{
string filePath = "output.txt";
try
{
// Create a StreamWriter instance (this will create or overwrite the file)
using (StreamWriter writer = new StreamWriter(filePath))
{
writer.WriteLine("Hello, this is the first line.");
writer.WriteLine("Second line of text.");
writer.WriteLine("Third line with some numbers: 12345");
// Write without a new line at the end
writer.Write("This text doesn't have a newline. ");
writer.Write("And this is on the same line.");
}
Console.WriteLine($"Successfully wrote to {filePath}");
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred: {ex.Message}");
}
}
}
After running this code, the file "output.txt" will contain:
Hello, this is the first line.
Second line of text.
Third line with some numbers: 12345
This text doesn't have a newline. And this is on the same line.
Appending to Files
To add content to an existing file without overwriting its contents:
using System;
using System.IO;
class Program
{
static void Main()
{
string filePath = "output.txt";
try
{
// Pass 'true' as the second parameter to append to the file
using (StreamWriter writer = new StreamWriter(filePath, true))
{
writer.WriteLine(); // Add an empty line
writer.WriteLine("This line is appended to the existing file.");
writer.WriteLine($"Current timestamp: {DateTime.Now}");
}
Console.WriteLine($"Successfully appended to {filePath}");
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred: {ex.Message}");
}
}
}
If you run this after the previous example, "output.txt" will now contain:
Hello, this is the first line.
Second line of text.
Third line with some numbers: 12345
This text doesn't have a newline. And this is on the same line.
This line is appended to the existing file.
Current timestamp: 5/20/2023 2:45:30 PM
Best Practices for File Handling
-
Always use
using
statements: This ensures that file handles are properly closed even if an exception occurs. -
Handle exceptions: File operations can fail for various reasons (permission issues, disk full, etc.). Always implement proper exception handling.
-
Check if files exist before reading: Use
File.Exists()
to verify if a file exists before attempting to read it. -
Be careful with file paths: Use
Path.Combine()
to create file paths instead of manually concatenating strings. -
Consider file encoding: If working with non-English text, specify the appropriate encoding:
// Reading with UTF-8 encoding
using (StreamReader reader = new StreamReader(filePath, System.Text.Encoding.UTF8))
{
// Read operations
}
// Writing with UTF-8 encoding
using (StreamWriter writer = new StreamWriter(filePath, false, System.Text.Encoding.UTF8))
{
// Write operations
}
Practical Examples
Example 1: Creating a Simple Log File
using System;
using System.IO;
class Logger
{
private string logFilePath;
public Logger(string filePath)
{
logFilePath = filePath;
}
public void LogMessage(string message)
{
try
{
using (StreamWriter writer = new StreamWriter(logFilePath, true))
{
writer.WriteLine($"[{DateTime.Now}] {message}");
}
}
catch (Exception ex)
{
Console.WriteLine($"Failed to write to log file: {ex.Message}");
}
}
}
class Program
{
static void Main()
{
Logger logger = new Logger("application.log");
logger.LogMessage("Application started");
// Simulate some application operations
logger.LogMessage("User login: john_doe");
logger.LogMessage("Database connection established");
// Simulate an error
try
{
int result = 10 / 0; // This will cause a division by zero exception
}
catch (Exception ex)
{
logger.LogMessage($"ERROR: {ex.Message}");
}
logger.LogMessage("Application shutdown");
Console.WriteLine("Check application.log for the log entries");
}
}
The output in "application.log" would look like:
[5/20/2023 3:01:45 PM] Application started
[5/20/2023 3:01:45 PM] User login: john_doe
[5/20/2023 3:01:45 PM] Database connection established
[5/20/2023 3:01:45 PM] ERROR: Division by zero
[5/20/2023 3:01:45 PM] Application shutdown
Example 2: CSV Data Processing
using System;
using System.IO;
using System.Collections.Generic;
class Student
{
public string Name { get; set; }
public int Age { get; set; }
public double GradeAverage { get; set; }
public override string ToString()
{
return $"{Name}, {Age}, {GradeAverage}";
}
}
class Program
{
static void Main()
{
string inputFile = "students.csv";
string outputFile = "high_performers.csv";
List<Student> students = new List<Student>();
// Read students from CSV
try
{
using (StreamReader reader = new StreamReader(inputFile))
{
// Skip header line
reader.ReadLine();
string line;
while ((line = reader.ReadLine()) != null)
{
string[] parts = line.Split(',');
if (parts.Length == 3)
{
Student student = new Student
{
Name = parts[0].Trim(),
Age = int.Parse(parts[1].Trim()),
GradeAverage = double.Parse(parts[2].Trim())
};
students.Add(student);
}
}
}
Console.WriteLine($"Read {students.Count} students from the file.");
// Filter high performing students (grade average > 85)
List<Student> highPerformers = students.FindAll(s => s.GradeAverage > 85);
// Write high performers to a new CSV file
using (StreamWriter writer = new StreamWriter(outputFile))
{
writer.WriteLine("Name,Age,GradeAverage");
foreach (Student student in highPerformers)
{
writer.WriteLine(student.ToString());
}
}
Console.WriteLine($"Wrote {highPerformers.Count} high performers to {outputFile}");
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred: {ex.Message}");
}
}
}
Let's assume that "students.csv" contains:
Name,Age,GradeAverage
John Smith,19,87.5
Mary Johnson,20,92.0
Robert Brown,18,79.3
Sarah Wilson,19,88.7
Michael Davis,21,76.2
After running the program, "high_performers.csv" would contain:
Name,Age,GradeAverage
John Smith, 19, 87.5
Mary Johnson, 20, 92
Sarah Wilson, 19, 88.7
Summary
In this tutorial, we've explored C# StreamReader
and StreamWriter
classes for file handling:
StreamReader
allows you to read text from files, either all at once or line by lineStreamWriter
enables you to write or append text to files- Always use
using
statements to ensure proper resource cleanup - Handle exceptions to make your code more robust
- Consider encoding when working with international text
These classes provide efficient ways to work with text files in C#, and are essential tools for many real-world applications, from logging to data processing.
Exercises
-
Create a program that counts the number of words, lines, and characters in a text file.
-
Write a program that reads a CSV file containing product data (name, price, quantity) and calculates the total inventory value.
-
Create a simple text editor that can open, edit, and save text files using
StreamReader
andStreamWriter
. -
Implement a program that merges multiple text files into a single file.
-
Create a log analysis tool that reads a log file and provides statistics about error occurrences.
Additional Resources
- Microsoft Documentation: StreamReader Class
- Microsoft Documentation: StreamWriter Class
- C# File Handling Tutorial
- Working with Text Files in C#
Happy coding!
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)