How to read from file in C#

The ability to read from file gives our C# programs the ability to act on data given by other programs, which may be written in different programming languages.

Such a ability is also helpful in allowing humans to configure how our C# program will behave at runtime.

Since being able to read from file is so helpful in C#, I want to remember how I can do that with this post.

Specifying file access

For file reads, we must use either the Read or the ReadWrite member of the System.IO.FileAccess enumeration to specify read access.

Specifying file mode

Apart from specifying file access, we specify the file mode via one of the members of the System.IO.FileMode enumeration. The file mode determines how the operating system will open the file for our code to read from.

Getting an instance of System.IO.FileStream

As with writing to file, there are a few ways which we can get code access to the file that we want to read from.

  • Using the System.IO.FileStream constructors.

    FileStream fileStream = new FileStream("techcoil.txt", 
        FileMode.Open, FileAccess.Read);
    
  • Using the static Open method of System.IO.File class.

    FileStream fileStream = File.open("techcoil.txt", 
        FileMode.Open, FileAccess.Read);
    
  • Using the Open method of the System.IO.FileInfo class.

    FileInfo fileInfo = new FileInfo("techcoil.txt");
    FileStream fileStream = fileInfo.Open(FileMode.Open, 
        FileAccess.Read);
    

The above code segments attempt to open techcoil.txt. If techcoil.txt does not exists, an instance of System.IO.IOException will be thrown.

Personally, I prefer using the last method as the FileInfo instance can provide me with useful information about the file. For instance, I can check whether the file exists before I attempt to gain code access to the file:

FileInfo fileInfo = new FileInfo("techcoil.txt");
// Check whether techcoil.txt exists                
if (fileInfo.Exists)
{
    FileStream fileStream = fileInfo.Open(FileMode.Open,
        FileAccess.Read);
    // Use fileStream to read data from file...
} 
else 
{
    Console.WriteLine("techcoil.txt does not exists.");
}

Reading text from file

Assuming that we want to read text from techcoil.txt and output the contents to console. The following code segment demonstrates how we can do this.

public class ReadTextFromFile
{
    public static void Main(string[] args)
    {
        try
        {
            FileInfo fileInfo = new FileInfo("techcoil.txt");
            // If techcoil.txt exists 
            if (fileInfo.Exists)
            {
                // Get an instance of FileStream that represents
                // techcoil.txt
                FileStream fileStream = fileInfo.Open(FileMode.Open,
                    FileAccess.Read);
                // Encapsulate the file stream instance in a StreamReader
                // instance
                StreamReader reader = new StreamReader(fileStream);
                String line;

                // Read the file, line by line
                while ((line = reader.ReadLine()) != null)
                {
                    // Print out the line to console
                    Console.WriteLine(line);
                } // end while
                
                reader.Close();
            }
            else
            {
                Console.WriteLine("techcoil.txt does not exist.");
            } // end if
        }
        catch (IOException ioe) {
            Console.WriteLine(ioe);
        } // end try-catch

    } // end public static void Main(string[] args)
} // end class public class ReadTextFromFile

The code segment starts by checking whether techcoil.txt exists. If it exists, an instance of the FileStream class is created via the FileInfo instance. The FileStream instance is then encapsulated in a System.IO.StreamReader instance, which is capable of reading text.

When the code is able to get read access to the file, the while loop reads the contents of the file and output to the console, line by line. When there are no more lines to read, reader.ReadLine returns null.

Reading binary data from file

We can use the Read method from the FileStream instance to read binary data from the file. Let's demonstrate this through a file copy example.

public class ReadBinaryDataFromFile
{
    public static void Main(string[] args)
    {
        try
        {
            FileInfo fileInfo = new FileInfo("techcoil.txt");
                
            if (fileInfo.Exists)
            {
                byte[] buffer = new byte[1024];

                // Get read access to file to copy from
                FileStream srcFileStream = new FileStream("techcoil.txt", 
                    FileMode.Open, FileAccess.Read);
                
                // Get write access to new file to copy to
                FileStream destFileStream = new FileStream("techcoil_new.txt", 
                    FileMode.Create, FileAccess.Write);

                int bytesRead;
                while((bytesRead = srcFileStream.Read(buffer, 0, buffer.Length)) != 0) {
                    Console.WriteLine("File copying in progress");
                    // Write the bytes read to new file
                    destFileStream.Write(buffer, 0, bytesRead);
                } // end while

                srcFileStream.Close();
                destFileStream .Close();
            }
            else
            {
                Console.WriteLine("techcoil.txt does not exist");
            } // end if
        }
        catch (IOException ioe) {
            Console.WriteLine(ioe);
        } // end try-catch
    } // end public static void Main(string[] args)
} // end public class ReadBinaryDataFromFile

The code segment starts by checking the existence of techcoil.txt - the source file to copy data from. If techcoil.txt exists, a 1024-sized byte array is set aside to hold data during file reads. Two FileStream instances are then created, one having read access to techcoil.txt; the other having write access to techcoil_new.txt - the destination file to copy data to. When both the files can be accessed for reading and writing, the program proceeds on with copying data from techcoil.txt to techcoil_new.txt.

In the while loop, srcFileStream.Read populates buffer with data, starting from the first element position (at index 0) to the last element position, where possible. It returns the number of bytes copied to buffer.

Some reflects about this post

Why do we use Console.WriteLine instead of Console.Write to output the content read by reader.ReadLine?

The ReadLine method will remove the new line character that denotes the end of line. By using Console.WriteLine, we put back the new line character onto the console screen.

Instead of getting a FileStream instance, can we get a StreamReader instance directly?

Yes, there are a couple of ways to get a StreamReader instance directly.

  • Use the OpenText() method of the fileInfo instance.
    FileInfo fileInfo = new FileInfo("techcoil.txt");
    StreamReader reader = fileInfo.OpenText();
    
  • Use the static OpenText() method of the File class.
    StreamReader reader = File.OpenText("techcoil.txt");
    
  • Use the StreamReader constructor

    StreamReader reader = new StreamReader("techcoil.txt");
    

Instead of manually doing binary data file copy, is there a shorter way to perform file copy?

Yes, we can use the System.IO.File.Copy method to perform the file copy:

File.Copy("techcoil.txt", "techcoil_new.txt", true);

The above code segment will copy the contents of techcoil.txt to techcoil_new.txt. A true value given as the third parameter indicates that if techcoil_new.txt exists, it's content will be overridden.

Why do we bother with manually copying the binary data file when there is a fast and easy way of doing so?

One reason for doing so is when it is necessary to provide feedback to the file copying progress to user, especially when copying very large file. Another situation that I could recall was trying to send a large multipart HTTP request to a server endpoint. By performing the binary read directly, I can show my user how many bytes had been read from file and how many bytes had been sent to the HTTP server endpoint.

Related posts

About Clivant

Clivant a.k.a Chai Heng enjoys composing software and building systems to serve people. He owns techcoil.com and hopes that whatever he had written and built so far had benefited people. All views expressed belongs to him and are not representative of the company that he works/worked for.