C# StreamWriter
last modified October 18, 2026
In this article we show how to write text files in C# with
StreamWriter. The C# tutorial is a
comprehensive tutorial on the C# language.
Input and output in C# is based on streams. A Stream is an abstract
base class of all streams. A stream is an abstraction of a sequence of bytes, such
as a file, an input/output device, an inter-process communication pipe, or a
TCP/IP socket.
C# StreamWriter
StreamWriter writes characters to a stream in a particular encoding.
It defaults to UTF-8 without a byte order mark (BOM) unless specified otherwise.
It buffers its output, so data may not reach the file until the buffer is flushed
or the writer is disposed. To read text files, use
StreamReader.
For a simple one-shot write, the File.WriteAllText,
File.WriteAllLines, and File.AppendAllText methods are
shorter. StreamWriter is the better choice when we write
incrementally, in a loop, or to a stream that is not a file.
C# StreamWriter example
The WriteLine method writes a string followed by a line terminator to
the stream. There are many overloads of WriteLine for different
types.
var path = "data.txt";
using var sw = new StreamWriter(path);
sw.WriteLine("old falcon");
sw.WriteLine("stormy night");
Console.WriteLine("data written to file");
The example writes two lines to the data.txt file.
using var sw = new StreamWriter(path);
A StreamWriter is created. If the file exists, it is overwritten;
otherwise it is created. The using declaration disposes the writer at
the end of the enclosing scope, which flushes the buffer and closes the file.
sw.WriteLine("old falcon");
sw.WriteLine("stormy night");
Two lines are written to the stream.
$ dotnet run data written to file $ cat data.txt old falcon stormy night
C# StreamWriter write formatted string
We can write formatted text with interpolated strings, or with the composite
format overload of WriteLine, which works like
string.Format. The Write method writes without a line
terminator.
Visit the C# string format tutorial to learn more about formatting in C#.
int n = 3;
string word = "hawks";
double temp = 21.456;
using var sw = new StreamWriter("data.txt");
sw.WriteLine($"There are {n} {word} in the sky");
sw.WriteLine("The temperature is {0:F1} degrees", temp);
sw.Write("no newline");
sw.Write('.');
sw.WriteLine();
Console.WriteLine("data written to file");
The example writes formatted lines to the file.
sw.WriteLine($"There are {n} {word} in the sky");
An interpolated string embeds the values directly in the text.
sw.WriteLine("The temperature is {0:F1} degrees", temp);
The composite format uses indexed placeholders. The F1 format
specifier rounds the number to one decimal place.
sw.Write("no newline");
sw.Write('.');
sw.WriteLine();
Write adds text to the current line; the final empty
WriteLine ends it.
$ dotnet run data written to file $ cat data.txt There are 3 hawks in the sky The temperature is 21.5 degrees no newline.
Numbers are formatted using the current culture. To get the same output on every
machine, format the values with
CultureInfo.InvariantCulture, for example
FormattableString.Invariant($"...").
C# StreamWriter append text
We can create a StreamWriter that appends text to the end of an
existing file.
public StreamWriter(string path, bool append);
If append is true and the file exists, the data is added
to the end of the file. If the file does not exist, it is created. If
append is false, an existing file is overwritten.
var path = "words.txt";
using (var sw = new StreamWriter(path, append: true))
{
sw.WriteLine("hawk");
}
using (var sw = new StreamWriter(path, append: true))
{
sw.WriteLine("falcon");
}
Console.WriteLine(File.ReadAllText(path));
The example appends two words to the words.txt file with two
separate writers.
using (var sw = new StreamWriter(path, append: true))
{
sw.WriteLine("hawk");
}
We open the writer in append mode. The using block ends at the closing
brace, so the file is closed before we open it again.
$ dotnet run hawk falcon $ dotnet run hawk falcon hawk falcon
Each run adds two more lines. The empty line at the end is the line terminator of
the last WriteLine plus the one added by
Console.WriteLine.
C# StreamWriter encoding
The third constructor argument selects the encoding. By default, UTF-8 is used without a byte order mark. We can ask for a BOM or choose a different encoding.
using System.Text;
var path = "data-latin2.txt";
var enc = Encoding.Latin1;
using (var sw = new StreamWriter(path, false, enc))
{
sw.WriteLine("café");
}
byte[] bytes = File.ReadAllBytes(path);
Console.WriteLine(BitConverter.ToString(bytes));
using (var sw = new StreamWriter("data-utf8.txt", false, new UTF8Encoding(encoderShouldEmitUTF8Identifier: true)))
{
sw.WriteLine("café");
}
Console.WriteLine(BitConverter.ToString(File.ReadAllBytes("data-utf8.txt")));
We write the word "café" in two encodings and inspect the raw bytes.
using (var sw = new StreamWriter(path, false, enc))
The second argument is the append flag, the third is the encoding. Latin-1 (ISO-8859-1) stores the character "é" as the single byte E9.
new UTF8Encoding(encoderShouldEmitUTF8Identifier: true)
This UTF-8 encoding emits the BOM EF BB BF at the beginning of the
file. Some Windows tools expect it; most other tools do not need it. In UTF-8, the
character "é" takes two bytes, C3 A9.
$ dotnet run 63-61-66-E9-0A EF-BB-BF-63-61-66-C3-A9-0A
C# StreamWriter async
For I/O-bound code, such as writing to slow storage or to a network stream, we can use the asynchronous methods so the calling thread is not blocked.
var path = "numbers.txt";
await using (var sw = new StreamWriter(path))
{
for (int i = 1; i <= 5; i++)
{
await sw.WriteLineAsync($"line {i}");
}
}
Console.WriteLine(await File.ReadAllTextAsync(path));
The example writes five lines asynchronously.
await using (var sw = new StreamWriter(path))
{
for (int i = 1; i <= 5; i++)
{
await sw.WriteLineAsync($"line {i}");
}
}
StreamWriter implements IAsyncDisposable, so we use
await using; the final flush is then asynchronous as well. Mixing
synchronous calls with an asynchronous disposal, or the other way around, defeats
the purpose.
$ dotnet run line 1 line 2 line 3 line 4 line 5
C# StreamWriter flush
A StreamWriter keeps characters in an internal buffer. The
Flush method writes the buffer to the underlying stream. Setting
AutoFlush to true flushes after every write call; this is
safer for logs, but slower.
var path = "log.txt";
using var sw = new StreamWriter(path) { AutoFlush = true };
sw.WriteLine("first message");
Console.WriteLine($"on disk after AutoFlush: {new FileInfo(path).Length} bytes");
using var sw2 = new StreamWriter("log2.txt");
sw2.WriteLine("buffered message");
Console.WriteLine($"on disk before Flush: {new FileInfo("log2.txt").Length} bytes");
sw2.Flush();
Console.WriteLine($"on disk after Flush: {new FileInfo("log2.txt").Length} bytes");
We compare a writer with AutoFlush turned on with a buffered writer.
using var sw = new StreamWriter(path) { AutoFlush = true };
The data reaches the file immediately after each write.
sw2.WriteLine("buffered message");
Console.WriteLine($"on disk before Flush: {new FileInfo("log2.txt").Length} bytes");
sw2.Flush();
Without AutoFlush, the file is still empty until we call
Flush (or dispose the writer).
$ dotnet run on disk after AutoFlush: 14 bytes on disk before Flush: 0 bytes on disk after Flush: 17 bytes
The sizes include the line terminator; on Windows, which uses two characters for a newline, they would be one byte larger per line.
C# StreamWriter with FileStreamOptions
Since .NET 6, StreamWriter can be created from a
FileStreamOptions object, which gives control over the file mode,
access, sharing, and buffer size without creating a FileStream
manually.
var path = "report.csv";
var cars = new (string Name, int Price)[]
{
("Audi", 52642), ("Mercedes", 57127), ("Skoda", 9000)
};
var opts = new FileStreamOptions
{
Mode = FileMode.Create,
Access = FileAccess.Write,
Share = FileShare.Read
};
using (var sw = new StreamWriter(path, opts))
{
sw.WriteLine("name,price");
foreach (var (name, price) in cars)
{
sw.WriteLine($"{name},{price}");
}
}
Console.WriteLine(File.ReadAllText(path));
We write a small CSV file.
var opts = new FileStreamOptions
{
Mode = FileMode.Create,
Access = FileAccess.Write,
Share = FileShare.Read
};
The file is created or truncated, opened for writing, and other processes may read it while we write.
$ dotnet run name,price Audi,52642 Mercedes,57127 Skoda,9000
Source
In this article we have written text files in C# with StreamWriter.
Author
List all C# tutorials.