This is an archived tutorial from the kirupa.com legacy collection. It covers software that may no longer be available, but it is kept online because the ideas still hold up.
Files are more than the documents you create in a word processor, images you design, source files you write, etc. They are not restricted to things you create or read, for almost everything you do on your computer directly or indirectly involves manipulating files. To view this HTML page, your browser received a file filled with HTML text. Your operating system uses a huge file to cache often-used pieces of data. When you compile your applications, the end result is a series of files that you as a human cannot read with a standard text editor.
More often than not, it is programs that are the intended readers for many files, and many programs write their own files in the background for various reasons. In this tutorial, you will learn how to write programs that read text from files and write text back to files using the StreamReader and StreamWriter Classes.
In most operating systems, a file is associated with a particular application designated to read it. When reading a file, an application takes the collection of data and loads it into memory for further processing. When an application is said to read a file, the file's contents may loaded sequentially in fixed chunks, or the entire file may be loaded into memory and read in bulk. These details aren't too important for us, because the .NET classes we use take care of a lot of these details for us, but it is good to have a brief idea of what is possible beyond what this tutorial will cover.
To read a file, you need to know only the path of a file. Once you have the path to a file, you load the file into memory until there is nothing more to load. To facilitate this, you have the System.IO namespace's StreamReader class that provides a lot of the functionality needed to read a file for you.
First, find a text file. If you cannot find a text file, copy and paste the following Dave Barry quote into Notepad and save it into an easily accessible location:
For this example, I saved the above quote on my Desktop and called it quote.txt. With your text file set, the following code sample shows you how to read a file from your drive:
StreamReader reader = new StreamReader("C:\\Users\\Kirupa\\Desktop\\quote.txt");
string readerLine = reader.ReadLine();
while (readerLine != null)
{
Console.WriteLine(readerLine);
readerLine = reader.ReadLine();
}
When I run through the above code, I see each line from my quote.txt file displayed in the console:

[ the Console output ]
In the next section, I will go through the code line-by-line and provide any interesting details and alternative approaches.
In the previous section I provided some minor background information on what files are, and more importantly, you got to see an example of the code used to read a text file. In this page, I will explain what each line of code does and begin talking about how to write text files.
StreamReader reader = new StreamReader("C:\\Users\\Kirupa\\Desktop\\quote.txt");
First, let's create a reader object that is of type StreamReader. As part of the StreamReader constructor, I am passing in the path to my text file. Notice that the folders in the path are not separated by single slashes as C:\Users\Kirupa\Desktop\quote.txt. Instead, the folder paths are delimited by double slashes because of the way strings in .NET are parsed. You will receive an error if you attempt to keep the path using single-slashes.
Another common way to deal with string-based paths is by using the @ symbol. The @ symbol allows you to treat strings literally without having them be parsed. With this modification, our code would look like the following:
StreamReader reader = new StreamReader(@"C:\Users\Kirupa\Desktop\quote.txt");
Notice that I am no longer using double-slashes because the @ symbol before our quotes informs the compiler to not parse the string.
string readerLine = reader.ReadLine();
Next, I create a new string variable called readerLine. I initialize readerLine to the first line from our text file by using the reader object's ReadLine() method.
while (readerLine != null)
{
Console.WriteLine(readerLine);
readerLine = reader.ReadLine();
}
The above loop is where the main reading of your file takes place. The loop will run as long as our readerLine variable still holds some text from our text file. As you progress through the loop, you set the readerLine variable equal to the next line from our text file by using the ReadLine() method.
Once you reach the end of your text file, reader.ReadLine() will return a null because there are no more lines of text to show. Once the null value is returned, our readerLine variable also equals null, and if you recall, our loop only loops when readerLine is not equal to null!
Reading a file is fairly straightforward. The only thing to watch out for is making sure you are ending your loop properly. Common mistakes I've made include forgetting to initialize the readerLine variable to the first line of text prior to looping. That causes your loop to break immediately. Another mistake I made is forgetting to set the readerLine variable equal to the next line inside the loop.
Besides what I listed above, reading files should is pretty straightforward. Of course, reading files is only half the fun! In the next section, you will learn how to use code to write text to a file.
In the previous section, you learned what each line of code used in our 'reading a file' example does. In this page, let's learn about the other big part of this tutorial - writing files.
In this section, you will learn how to take string data and write it to a file. While writing a file seems more complicated, it actually takes fewer steps than when you are reading a file.
To write a file, all you really need to do is specify the location of your saved file and have some text that you need to write:
StreamWriter writer = new StreamWriter("C:\\Users\\Kirupa\\Desktop\\foo.txt");
writer.WriteLine("Hello world!");
writer.Close();
Let's dive right into what the code actually does:
StreamWriter writer = new StreamWriter("C:\\Users\\Kirupa\\Desktop\\foo.txt");
In this line, I create a new StreamWriter object called writer. The StreamWriter constructor takes a file as an argument. The file you specify is where your data will be written to. If the file you specify does not exist, that file will be created automatically for you. If the file already exists, and no other program is currently accessing it, you will overwrite it.
writer.WriteLine("Hello world!");
In this line, you specify the text to write to your file. The WriteLine method can take a string as its argument, and in the above line, I am passing in the text "Hello World!"
writer.Close();
In this line, we commit the change we made by closing the connection. If you do not close the StreamWriter object, any text you write or modifications you make will not be saved.
As you can see, writing a line of text to a file is not too complicated. The main thing to remember is that there is no functionality to append data to the end of a file. Any data you add overwrites the existing file with the new data, so unless you want to lose your data, make sure to read and store the existing data first.
You cannot read a file that does not exist, and you may not want to overwrite an existing file. Both of these scenarios can be avoided by checking if the file you are writing to exists first. You can check if a File exists by using File.Exists():
string filePath = "C:\\Users\\Kirupa\\Desktop\\foo.txt");
if (File.Exists(filePath))
{
// File exists
}
else
{
// File does not exist
}
In the next section, I will provide some more information concerning checking how a file exists and wrap it up with a brief discussion on the asynchronous properties of the StreamReader and StreamWriter classes.
In the previous section you learned how to write files, and I began talking about how to check if a file exists. In this page, I'll continue from where we left off and talk more about checking whether files exist.
Something to remember is that a file is created or overwritten when your StreamWriter is initialized with the path to your file. Therefore, something like the following will not work like you would want to:
string filePath = "C:\\Users\\Kirupa\\Desktop\\foo.txt";
StreamWriter foo = new StreamWriter(filePath);
if (File.Exists(filePath))
{
// File exists
}
else
{
// File does not exist
}
The reason is that the moment your StreamWriter object foo is initialized, the file pointing to by filePath will be created or overwritten. Our File.Exists boolean will always return true because no matter what you reasonably do, a file at filePath will exist.
If you want to avoid overwriting an existing file, the following approach works better:
string filePath = "C:\\Users\\Kirupa\\Desktop\\foo.txt";
StreamWriter foo;
if (File.Exists(filePath))
{
// File exists
// Don't do anything.
}
else
{
// File does not exist
foo = new StreamWriter(filePath);
foo.Write("Blarg. Zorb. Zeeb. Foo.");
foo.Close();
}
In the above code, a file is created only if File.Exists returns false. Notice that our StreamWriter object foo isn't being initialized until our code reaches the File.Exists == false condition.
Both the StreamReader and StreamWriter classes work asynchronously. That's a cool sounding word that basically means that you can do other things when using StreamReader or StreamWriter. To take a real world example, if you were opening a huge text file, you can continue to use your application and everything will seem to work fine without suffering delays or lags associated with reading your file.
If both of those classes were not asynchronous, then you would have to use Threads to ensure any time consuming reading or writing task operates semi-independently from other tasks. Threads is an interesting topic that I will save for a later article.
Just a final word before we wrap up. What you've seen here is freshly baked content without added preservatives, artificial intelligence, ads, and algorithm-driven doodads. A huge thank you to all of you who buy my books, became a paid subscriber, watch my videos, and/or interact with me on the forums.
Your support keeps this site going! 😇

:: Copyright KIRUPA 2026 //--