StreamReader Read Specific Line

CUSTOM METHOD TO READ A SPECIFIC LINE OF A TEXT FILE

by

In this tutorial, you will learn how to use the StreamReader object to read a specific line number of a text file in your C# applications.

Recall that StreamReader can be used to read the contents of a text file in C#. The class has methods for reading individual characters, reading to the end of the file, and for reading individual lines. For this tutorial, we will be concerned with the ReadLine() method.

The StreamReader ReadLine() Method

The ReadLine() method of the StreamReader class reads a single line of a stream and returns the contents of that line as a string. Specifically, it reads the line corresponding to the current position of the stream pointer.

When a file is first opened, the pointer is at the beginning of the file. Therefore, the first use of ReadLine() will return a string containing the first line of the document.

Unfortunately, the ReadLine() method does not have an overloaded constructor that can simply accept a line number as an argument. Rather, in order to read a specific line number of a text file or stream, some trickery is required.

Read Specific Line

Remember that ReadLine() reads the line at current cursor position and then advances the cursor to the next line. To read a specific line, you can invoke ReadLine() for each line you need to skip. This approach will pass over and discard all the lines you are not interested in. Then, once the cursor is in the desired location, you can invoke ReadLine() once more to capture the line you wish to process, but this time don't forget to save the value.

First, include the System.IO directive in your project in order to use the StreamReader class.

using System;
using System.IO;

The basic technique for reading a specific line of a text file in C# will look like the following code fragment. Notice this fragment does not have error handling. Continue reading for a more robust version.

using (StreamReader inputFile = new StreamReader(filePath))
{
    //Skipping all lines we are not interested in
    for (int i = 1; i < lineNumber; i++)
    {
        inputFile.ReadLine();
    }
 
    //Specific line we want to read
    Console.WriteLine(inputFile.ReadLine());
}

On Line 10, you will see that the File I/O processing is enclosed in a using statement to ensure that the StreamReader object is properly disposed once the file is read.

The For Loop code block, Lines 13-16, is used to skip over all the lines up until the one specified by the integer variable lineNumber. Notice that indexing in this for-loop begins with 1 instead of 0. This is because that is the way people typically count line numbers. Line 15, then, is executed one time for each line in the file up until the one you want to read, but you are not doing anything with the value. Basically, this for-loop just advances the file position cursor.

After the for-loop, the file position pointer is on the desired line. You can now do something with the line you want to read. In this case, the line is printed to the console on Line 19.

Read Specific Line with Error Handling

The version above does not have error handling. If the file does not exist, for example, an exception will be thrown and your program will crash. The following example is a more complete option.

static void Main(string[] args)
{
    string filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "ReadFile.txt");
    int lineNumber = 3;
    try
    {
        using (StreamReader inputFile = new StreamReader(filePath))
        {
            for (int i = 1; i < lineNumber; i++)
            {
                inputFile.ReadLine();
            }
 
            Console.WriteLine(inputFile.ReadLine());
        }
    }
    catch (IOException e)
    {
        Console.WriteLine("There was an error reading the file: ");
        Console.WriteLine(e.Message);
    }
 
    Console.ReadLine();
}

In this example, you will use the same technique as above to read line 3 of a text file, but you will enclose the file I/O code in a try/catch block in order to appropriately handle IOException errors. In the try code block, your program attempts to open and read the file provided in the filePath string variable. In this case, it will try to open a file called ReadFile.txt located on the system's Desktop. The program passes over lines 1 and 2 of the document, and then prints line 3 to the console.

The catch block provides the error handling. If the file or directory is not found, a user-friendly error message will be written to the console explaining the nature of the exception. This single catch block will handle both FileNotFoundException and DirectoryNotFoundException exceptions, as well as other general IOException exceptions. You could also add a separate catch block for each of these types of errors in order to uniquely handle these different exceptions.

C# Method for Reading Specific Line of Text File

The above example works fine for simple C# projects, but suppose you want to use the code to read specific lines in multiple text files throughout your project. It would be helpful to create a method that receives as parameters a file path and a line number to read.

Given a file and a line number, the method should return a string corresponding to that line number. If there are any errors, the user should be notified with details about error.

static string ReadSpecificLine(string filePath, int lineNumber)
{
    string content = null;
    try
    {
        using (StreamReader file = new StreamReader(filePath))
        {
            for (int i = 1; i < lineNumber; i++)
            {
                file.ReadLine();
 
                if (file.EndOfStream) {
                    Console.WriteLine($"End of file.  The file only contains {i} lines.");
                    break;
                }
            }
            content = file.ReadLine();
        }
 
    }
    catch (IOException e)
    {
        Console.WriteLine("There was an error reading the file: ");
        Console.WriteLine(e.Message);
    }
 
    return content;
    
}

What type of errors does this method handle? First, if the user requests a line number that does not exist in the file, an error message will be written to the console (Line 12-15). Second, if an invalid file location is passed to the function, it will catch this exception (Line 21-25) and print the error message to the console. In either of these two cases, the method will return a null string.

To use this method, simply pass it the location of a file (as a string) and the line number to read (as an int).

static void Main(string[] args)
{
    string filePath = "C:/Users/wellsb/Desktop/ReadFile.txt";
    int lineNumber = 3;
 
    string lineContents = ReadSpecificLine(filePath, lineNumber);
 
    if (lineContents != null)
        Console.WriteLine(lineContents);
 
    Console.ReadLine();
}

Line 13 invokes the method you just created. You only need to do something with the returned string if the contents are not null (Line 15). When the method returns a null string, an error has occurred and the user will have already been notified.

The Bottom Line

In this tutorial, you learned how to use the C# StreamReader class to read a specific line from a text file. You learned about ReadLine() method, and how to use it to skip over lines in a stream. You also learned how to do error handling for a file I/O operation. Finally, you created a robust method that can be used across your application any time you need to read a specific line from a document. Was this technique helpful in your project? Tell me about it in the comments!


Don't stop learning!

There is so much to discover about C#. That's why I am making my favorite tips and tricks available for free. Enter your email address below to become a better .NET developer.


Did you know?

Our beautiful, multi-column C# reference guides contain more than 150 tips and examples to make it even easier to write better code.

Get your cheat sheets