.Net Programming - Financial independence

Access Files with the FileStream in C#/Visual Basic

It’s very useful to know how to access files in C# and Visual Basic. You’ll see it’s not that difficult! In this post I’ll show you how to write to a file and read its content right after, it’s like magic but for real! To accomplish this task we’ll use a more barebone combination of the FileStream, StreamWriter and StreamReader classes.

1. Setup!

To start simply, create a Console type application (.Net Framework with Visual Basic or C#).

New .Net Framework Console project.

Just a quick note for Visual Basic, by default Visual Studio will create a Module named Module1, you might want to rename that module to something like: Program.vb a bit like in C#. Right-click on the file in Solution Explorer and click on Rename, then hit Yes when asked to rename references.

Rename File in Visual Basic.

2. Create a FileStream

To access a file you will first need to create an input output stream. You can view this stream as a link between your program and the file you’re trying to do operations on. We have two choices here, we could use the File static class or we could use the FileStream class.

I’ll show how the FileStream class since the File class uses one in the background.

C#

using System;
using System.Collections.Generic;
using System.IO;

namespace ConsoleFileAccess
{
    class Program
    {
        static void Main(string[] args)
        {
            string targetFilePath = "text.txt";

            FileStream fileStream = new FileStream(targetFilePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
        }
    }
}

Note: for C# the namespace ConsoleFileAccess might be different for you if the name of your project is not ConsoleFileAccess.

Visual Basic

Imports System.IO

Module Program

    Sub Main()
        Dim targetFilePath As String = "text.txt"

        Dim fileStream As New FileStream(targetFilePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None)
    End Sub

End Module

In the code above, we create the base FileStream to access the data. Here are the different parts of the FileStream constructor that we’re using.

  • The path, well it’s the path to the file you want to create a link to! It can be absolute: exact path to the file, OR relative: where the .exe is currently located.
  • FileMode will specify what we want to do with the file. In this case we’ll want to write information using the FileStream. Here we want to either create the file if it does not exist or open it if it already does.
  • FileAccess will limit the capabilities of the FileStream to what we actually want to do. Here we will start by writing to the file.
  • FileShare will indicate to the operating system what others wanting to access this file can do, in our case it’s none so they will not be able to access the file at the same time until we close the stream.

Remember that this is the link between our program and the file we want to access, as long as this remains open we can operate but might be limiting other processes depending on the FileShare parameter. Next, we’ll need to either read or write to the file. We’ll start by writing some information. For that we’ll need a StreamWriter!

3. The StreamWriter

As you might have guessed the StreamWriter is needed to write data to a Stream. In our case it’s a FileStream type of Stream so we will attach both together as follow. While we’re at it, there are different kinds of Streams that you can use and they will all work with the StreamWriter as long as they inherit the Stream base class.

StreamWriter Constructor taking FileStream in parameter.

C#

using System;
using System.Collections.Generic;
using System.IO;

namespace ConsoleFileAccess
{
    class Program
    {
        static void Main(string[] args)
        {
            string targetFilePath = "text.txt";

            // StreamWriter
            // Initialize the FileStream and the associated StreamWriter.
            FileStream fileStream = new FileStream(targetFilePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
            StreamWriter streamWriter = new StreamWriter(fileStream);
        }
    }
}

Visual Basic

Imports System.IO

Module Program

    Sub Main()
        Dim targetFilePath As String = "text.txt"

        ' StreamWriter
        ' Initialize the FileStream And the associated StreamWriter.
        Dim fileStream As New FileStream(targetFilePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None)
        Dim streamWriter As New StreamWriter(fileStream)
    End Sub

End Module

In the code above, we pass the FileStream we’ve declared directly to our StreamWriter object constructor to be used. That way the StreamWriter knows where it needs to write!

Write or WriteLine

Now we could use either of the methods, Write will simply write data in the file while WriteLine will add carriage return/line feed (\r\n) at the end. We’ll use WriteLine for the example because I want to write a list of students to the file, one student per line.

C#

using System;
using System.Collections.Generic;
using System.IO;

namespace ConsoleFileAccess
{
    class Program
    {
        static void Main(string[] args)
        {
            string targetFilePath = "text.txt";

            // StreamWriter
            // Initialize the FileStream and the associated StreamWriter.
            FileStream fileStream = new FileStream(targetFilePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
            StreamWriter streamWriter = new StreamWriter(fileStream);

            // Create a new list of students.
            List<string> students = new List<string>();

            students.Add("Alex");
            students.Add("John");
            students.Add("Jason");

            // Write the name of each student in the file.
            foreach (string studentName in students)
                streamWriter.WriteLine(studentName);

            // Flush is not mandatory unless you want to put the data from the buffer to the file. Else Close will execute this action. 
            streamWriter.Flush();
            // You can simply close the StreamWriter as it will close the link to the file (FileStream) at the same time!
            streamWriter.Close();
        }
    }
}

Visual Basic

Imports System.IO
Imports System.Collections.Generic

Module Program

    Sub Main()
        Dim targetFilePath As String = "text.txt"

        ' StreamWriter
        ' Initialize the FileStream And the associated StreamWriter.
        Dim fileStream As New FileStream(targetFilePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None)
        Dim streamWriter As New StreamWriter(fileStream)

        ' Create a new list of students.
        Dim students As New List(Of String)

        students.Add("Alex")
        students.Add("John")
        students.Add("Jason")

        'Write the name of each student in the file.
        For Each studentName As String In students
            streamWriter.WriteLine(studentName)
        Next

        ' Flush is not mandatory unless you want to put the data from the buffer to the file. Else Close will execute this action. 
        streamWriter.Flush()
        ' You can simply close the StreamWriter as it will close the link to the file (FileStream) at the same time!
        streamWriter.Close()
    End Sub

End Module

Flush() will simply dump whatever is in the memory buffer into the file and make it “real” on the disk. Then Close() will close the StreamWriter and the FileStream at the same time so you don’t have to close both.

When you think about it, it’s kind of like writing in the console!

Here is the resulting file if you execute the code above. By the way, the file will be in your project’s directory (right-click on your solution -> Open Folder in File Explorer) then go to bin\Debug and you’ll find it! This is because we’re using the relative path and the .exe is in the bin\Debug folder of the Solution.

Result of the StreamWriter WriteLine Operation.

Pretty cool isn’t it! Now every time you run the program it’s going to crush part of whatever information you had in the file and replace it by what you’ve just entered. I’m saying “part” because let’s say we remove Jason from the list of students to write, then run the program again, it will still be in the file! That’s because it’s writing over the information we already have starting at position 0.

C#

//students.Add("Jason");

Visual Basic

'students.Add("Jason")

Create and Append

To fix this issue, if you want to always have a brand new file or always add information at the end of the file, you’ll need to modify the FileMode to Create or Append respectively.

Result using the Create FileMode.

File Mode Create

Result using the Append FileMode.

File Mode Append.

You can see the difference between the two, create will always clear the file content then will start to write, append will go to the end of the file then will start to write. Feel free to explore the other file modes as they each have their own particularities.

4. The StreamReader

The StreamReader is also pretty self explanatory: it will read data from a Stream, in our case, a FileStream type of Stream. It’s used in a similar way to the StreamWriter, you will see.

C#

// StreamReader
// We declare another FileStream to use with the StreamReader.
FileStream readFileStream = new FileStream(targetFilePath, FileMode.OpenOrCreate, FileAccess.Read, FileShare.None);
StreamReader streamReader = new StreamReader(readFileStream);

// We can use ReadToEnd which will read from the start to the end of the file and conveniently return a string for us to use.
string fileContent = streamReader.ReadToEnd();

// Closing the StreamReader and this will also close the FileStream associated to it.
streamReader.Close();

// I'll display everything in the console.
Console.Write(fileContent);
Console.ReadKey();

Visual Basic

' StreamReader
' We declare another FileStream to use with the StreamReader.
Dim readFileStream As New FileStream(targetFilePath, FileMode.OpenOrCreate, FileAccess.Read, FileShare.None)
Dim streamReader As New StreamReader(readFileStream)

' We can use ReadToEnd which will read from the start to the end of the file and conveniently return a string for us to use.
Dim fileContent As String = streamReader.ReadToEnd()

' Closing the StreamReader and this will also close the FileStream associated to it.
streamReader.Close()

' I'll display everything in the console.
Console.Write(fileContent)
Console.ReadKey()

Same thing, we declare another FileStream object but notice the FileMode and the FileAccess that are different. We want to OpenOrCreate the file depending on if it exists or not and we’re looking to do a Read operation.

Here is the result we get from the previous code if you add it following the StreamWriter code.

StreamReader read results.

ReadToEnd

Honestly, the ReadToEnd method is most probably the one you’ll use very often as it simply reads from the beginning (or your current position) of the file to the end. If let’s say the file was too big to be handled you could accomplish the same task by using Read() which will read only one character at the time of ReadLine() to read line by line.

Another Way to Read The Content: ReadLine

As pointed above, you could also use ReadLine to read the content line by line, here is an example of how to use it.

C#

// Another way we could read all the text would be using ReadLine()
// Going back to the beginning of the Stream.
streamReader.BaseStream.Seek(0, SeekOrigin.Begin);

// Reading the whole file once again while outputting the read line into the console at the same time.            
while (!streamReader.EndOfStream)
    Console.WriteLine(streamReader.ReadLine());

// Closing the StreamReader and this will also close the FileStream associated to it.
streamReader.Close();

Visual Basic

' Another way we could read all the text would be using ReadLine()
' Going back to the beginning of the Stream.
Console.WriteLine("---Read line by line with ReadLine---")
streamReader.BaseStream.Seek(0, SeekOrigin.Begin)

' Reading the whole file once again while outputting the read line into the console at the same time.
While Not streamReader.EndOfStream
    Console.WriteLine(streamReader.ReadLine())
End While

' Closing the StreamReader and this will also close the FileStream associated to it.
streamReader.Close()

Notice the Seek method that we call from the BaseStream object in the StreamReader, this is used to go back to the beginning, you don’t have to call this method if you’ve just declared a new FileStream as it will already be at the beginning of the file.

Complete Code

Here is the complete code for the Program.cs and Program.vb files.

C#

using System;
using System.Collections.Generic;
using System.IO;

namespace ConsoleFileAccess
{
    class Program
    {
        static void Main(string[] args)
        {
            string targetFilePath = "text.txt";

            // StreamWriter
            // Initialize the FileStream and the associated StreamWriter.
            FileStream writeFileStream = new FileStream(targetFilePath, FileMode.Append, FileAccess.Write, FileShare.None);
            StreamWriter streamWriter = new StreamWriter(writeFileStream);

            // Create a new list of students.
            List<string> students = new List<string>();

            students.Add("Alex");
            students.Add("John");
            students.Add("Jason");

            // Write the name of each student in the file.
            foreach (string studentName in students)
                streamWriter.WriteLine(studentName);

            // Flush is not mandatory unless you want to put the data from the buffer to the file. Else Close will execute this action. 
            streamWriter.Flush();
            // You can simply close the StreamWriter as it will close the link to the file (FileStream) at the same time!
            streamWriter.Close();

            // StreamReader
            // We declare another FileStream to use with the StreamReader.
            FileStream readFileStream = new FileStream(targetFilePath, FileMode.OpenOrCreate, FileAccess.Read, FileShare.None);
            StreamReader streamReader = new StreamReader(readFileStream);

            // Use the Peek to check the next character. If there is no next character then it will return -1.
            int character = streamReader.Peek();
            Console.WriteLine($"The next character in the file is {(char)character}.");

            // We can use ReadToEnd which will read from the start to the end of the file and conveniently return a string for us to use.
            string fileContent = streamReader.ReadToEnd();
            Console.Write(fileContent);

            // Another way we could read all the text would be using ReadLine()
            // Going back to the beginning of the Stream.
            streamReader.BaseStream.Seek(0, SeekOrigin.Begin);

            // Reading the whole file once again while outputting the read line into the console at the same time.            
            while (!streamReader.EndOfStream)
                Console.WriteLine(streamReader.ReadLine());

            // Closing the StreamReader and this will also close the FileStream associated to it.
            streamReader.Close();

            Console.ReadKey();
        }
    }
}

Visual Basic

Imports System.IO
Imports System.Collections.Generic

Module Program

    Sub Main()
        Dim targetFilePath As String = "text.txt"

        ' StreamWriter
        ' Initialize the FileStream And the associated StreamWriter.
        Dim fileStream As New FileStream(targetFilePath, FileMode.Append, FileAccess.Write, FileShare.None)
        Dim streamWriter As New StreamWriter(fileStream)

        ' Create a new list of students.
        Dim students As New List(Of String)

        students.Add("Alex")
        students.Add("John")
        students.Add("Jason")

        'Write the name of each student in the file.
        For Each studentName As String In students
            streamWriter.WriteLine(studentName)
        Next

        ' Flush is not mandatory unless you want to put the data from the buffer to the file. Else Close will execute this action. 
        streamWriter.Flush()
        ' You can simply close the StreamWriter as it will close the link to the file (FileStream) at the same time!
        streamWriter.Close()

        ' StreamReader
        ' We declare another FileStream to use with the StreamReader.
        Dim readFileStream As New FileStream(targetFilePath, FileMode.OpenOrCreate, FileAccess.Read, FileShare.None)
        Dim streamReader As New StreamReader(readFileStream)

        ' We can use ReadToEnd which will read from the start to the end of the file and conveniently return a string for us to use.
        Console.WriteLine("---Read using ReadToEnd---")
        Dim fileContent As String = streamReader.ReadToEnd()

        ' I'll display the content of the file in the console.
        Console.Write(fileContent)

        ' Another way we could read all the text would be using ReadLine()
        ' Going back to the beginning of the Stream.
        Console.WriteLine("---Read line by line with ReadLine---")
        streamReader.BaseStream.Seek(0, SeekOrigin.Begin)

        ' Reading the whole file once again while outputting the read line into the console at the same time.
        While Not streamReader.EndOfStream
            Console.WriteLine(streamReader.ReadLine())
        End While

        ' Closing the StreamReader and this will also close the FileStream associated to it.
        streamReader.Close()

        Console.ReadKey()
    End Sub

End Module

To summarize quickly: The FileStream will indicate where and how to write in the File, the StreamWrite will write to the file and the StreamReader is used to read from the file.

Try to run the code and play with the different components with breakpoints. This will give you a better idea of what’s really going on. Don’t forget to call the Close() method to close the connection you have with the file (like I always do!). You might want to cover for the Close() method by adding the using keyword since the FileStream and the StreamWriter/StreamReader all implement the IDisposable interface. Here is a link to help you out, it’s very convenient you’ll see.

Where to Go from There?

If you need more information about the topic, you should check out the Microsoft Website as they have more examples over there. I’ll also continue to add more posts on input output in the future, you can have a look at everything on the .Net Programming page. Any other question? Then you might want to leave a comment or to send a message directly by using my contact form.

Happy coding everyone!

Found an error in the code? Please send me a message so I can fix it as soon as possible!

YouTube

Project Files

Download the following files to follow along with the project YouTube video!

Next article How to Use the "Just-in-time" Expense Theory
Previous article Using Join With LINQ in C#

Related posts

0 Comments

No Comments Yet!

You can be first to comment this post!

Leave a Comment

Your data will be safe! Your e-mail address will not be published. Also other data will not be shared with third person. Required fields marked as *