c sharp

How to Read and Write Files with C# FileStream

In C#, the FileStream class provides a stream for the file which enables the “sync” and “async” read and write file operations. The FileStream class is part of the System.IO namespace and it is one of the most powerful and useful classes when it comes to file operations in C#.

In this tutorial, we will walk you through all the most common and powerful operations that you can perform using the FileStream class in C#.

NOTE: It is good to understand that we mainly deal with bytes when working with the FileStream class. We can use the stream reader and writers for a more efficient way of handling the text data as we will cover in the upcoming sections.

Basics: Creating the FileStream

As you can guess, the first step is creating a new FileStream object. We do this using the FileStream constructor and pass the file path and the mode as arguments.

The class contains a set of constructors, each with a set of parameters. You can reference the supported constructors in the following documentation:

https://learn.microsoft.com/en-us/dotnet/api/system.io.filestream.-ctor?view=net-7.0

For our case, we can use the file path as a string and file permissions as shown in the following example:

using System.IO;
class Program
{
    static void Main()
    {
        FileStream fs = new FileStream("usernames.txt", FileMode.Create);
        fs.Close();
    }
}

In this case, we create the “fs” FileStream object which allows us to work with the file called “usernames.txt” in the current working directory. We also specify the “FileMode.Create” which tells the object to create the file if it does not exist. If the file already exists, the object overwrites it.

The Close() method allows us to close the FileStream object and release any system resources associated with the file.

Writing a FileStream to the File

Once we define a FileStream to a given file, we can use the “Write” method to process the data into the file. As mentioned, you need to convert any data that you wish to write into bytes as demonstrated in the following example:

using System.IO;
using System.Text;

class Program
{
    static void Main()
    {
        byte[] data = Encoding.UTF8.GetBytes("user1, user2, user3!");
        FileStream fs = new FileStream("usernames.txt", FileMode.Create);
        fs.Write(data, 0, data.Length);
        fs.Close();
    }
}

In the given example, we start by creating a byte array which contains the data that we wish to write. We use the Encoding.UTF8.GetBytes method to convert the provided string into bytes.

Finally, we create a new stream with the name of the file that we wish to write to and the file mode.

Using the “Write” method, we specify the byte array that we wish to write. We also specify the offset in the byte array at which we wish to begin writing. In this case, passing the offset to 0 ensures that we are writing to the file from the start of the array.

The last parameter in the function is the data.Length which sets the number of bytes to write. In this case, the function writes until the end of the byte array.

Reading a File in FileStream

It is pretty common to read the files from the file system using the FileStream. Luckily, we can just call the Read() method to read the file as shown in the following example:

using System.IO;
using System.Text;

class Program
{
    static void Main()
    {
        byte[] data = new byte[1024];
        FileStream fs = new FileStream("usernames.txt", FileMode.Open);
        int bytes = fs.Read(data, 0, data.Length);
        fs.Close();
        string content = Encoding.UTF8.GetString(data, 0, bytes);
        Console.WriteLine(content);
    }
}

In the given example, we start by creating a FileStream object with the name of the file that we wish to read and set the FileMode.Open as the file mode.

Next, we create a variable to store the data that we read from the file. This includes the offset and the bytes that we wish to read.

Lastly, we decode the data from bytes into a string and print them to the console.

Output:

user1, user2, user3!

Closing a FileStream

The best way to ensure that a FileStream is closed after use is using the “using” statement. You can check our tutorial on how to use the C# “using” keyword.

An example is as follows:

using System.IO;
using System.Text;

class Program
{
    static void Main()
    {
        using (FileStream fs = new FileStream("usernames.txt", FileMode.Create))
        {
            byte[] data = Encoding.UTF8.GetBytes("user1, user2, user3!");
            fs.Write(data, 0, data.Length);
        }
    }
}

In this case, we ensure to encapsulate the FileStream inside the “using” statement which then ensures that the stream is closed after use. This helps to release the resources that may be required when working with the file.

Using FileStream with StreamWriter

In C#, we have access to the StreamWriter which implements a TextWriter to write the characters to a stream in a given encoding. As you can guess, this class comes with its constructors, properties, methods, and more.

We can combine a FileStream and StreamWriter to create a simplistic and effective way of writing the data to a file as follows:

using System.IO;

class Program
{
    static void Main()
    {
        using (FileStream fs = new FileStream("usernames.txt", FileMode.Create))
        using (StreamWriter writer = new StreamWriter(fs))
        {
            writer.WriteLine("user1, user2, user3");
        }
    }
}

In the given example, we start by creating a FileStream object with the name and filemode that we wish to use.

Next, we create a StreamWriter object and pass a file handle for the current FileStream object encapsulation.

Lastly, we can call the writer.WriteLine() method to write the text into the file.

Using FileStream with StreamReader

As you can guess, we can also use the StreamReader to read a text from a file. We follow the same implementation as in the previous examples. But instead of “Write”, we use “Read”.

An example is as shown:

using System.IO;

class Program
{
    static void Main()
    {
        using (FileStream fs = new FileStream("usernames.txt", FileMode.Open))
        using (StreamReader reader = new StreamReader(fs))
        {
            string content = reader.ReadToEnd();
            Console.WriteLine(content);
        }
    }
}

This should read the data from the file as a string.

Appending a Data in FileStream

Instead of overwriting a file, we can append a new data to the existing one by simply setting the file mode to “Append” during the FileStream object creation.

using System.IO;
using System.Text;
class Program
{
    static void Main()
    {
        using (FileStream fs = new FileStream("usernames.txt", FileMode.Append))
        {
            byte[] data = Encoding.UTF8.GetBytes("newuser");
            fs.Write(data, 0, data.Length);
        }
    }
}

In this case, we use the file mode as “FileMode.Append” which prevents the stream from overwriting the file contents.

NOTE: Ensure that the file exists before attempting to append the data.

Copying the File in FileStream

We can also use the “CopyTo” method which allows us to read the bytes from the current stream and write them to another stream. This provides a file copy functionality as follows:

using System;
using System.IO;

class Program
{
    static void Main()
    {
        string sourceFilePath = "src.txt";
        string destinationFilePath = "dest.txt";
        using (FileStream sourceStream = new FileStream(sourceFilePath, FileMode.Open))
        using (FileStream destinationStream = new FileStream(destinationFilePath, FileMode.Create))
        {
            sourceStream.CopyTo(destinationStream);
            Console.WriteLine($"Content of {sourceFilePath} copied to {destinationFilePath}");
        }
    }
}

This example uses the “CopyTo” method to copy the contents of one stream into another.

NOTE: You need to ensure the source file that already exists on the filesystem before copying it.

Conclusion

In this tutorial, we explored the ins and outs of the FileStream in C# to discover how to handle and work with the files in a C# application.

About the author

John Otieno

My name is John and am a fellow geek like you. I am passionate about all things computers from Hardware, Operating systems to Programming. My dream is to share my knowledge with the world and help out fellow geeks. Follow my content by subscribing to LinuxHint mailing list