How do I read next x number of lines after finding a line using streamreader

94 Views Asked by At

I want to search a text file for a line containing "Performance Stats:" then print the next 20 or so as they are a table of performance stats. I'm using Streamreader.

string pathToFile = "\\host\c$\temp\logs\myPerformanceFile.txt"

using (var filestream = new FileStream(pathToFile, FileMode.Open, FileAccess.Read,                               FileShare.ReadWrite))
using (var streamReader = new StreamReader(filestream, Encoding.Default))
{
    string line;
    while ((line = streamReader.ReadLine()) != null)
    {
        if (line.Contains("Performance Stats:"))
        {
            Console.WriteLine(line)
        }
    }
}

I have tried to find the title column of each of the stats. But it looks a little messy for 20 lines e.g. and there are 5 tables in the file i'm parsing with the same search parms.. but I only want data from one of the tables.

        if (line.Contains("Timings:"))
        {
            Console.WriteLine(line)
        }
        if (line.Contains("Downloads:")) 
        {
            Console.WriteLine(line)
        }
        if (line.Contains("Reset")) 
        {
            Console.WriteLine(line)
        }
2

There are 2 best solutions below

1
SysDragon On BEST ANSWER

You can use a counter. For example:

int counter = 0; 

while ((line = streamReader.ReadLine()) != null)
{
    if (line.Contains("Performance Stats:")) // Trigger
    {
        counter = 20; // Number of lines to print
    }
    if (counter > 0) {
        Console.WriteLine(line);
        counter--;
    }
}

This way you can print the X next lines after your trigger.

If you put the trigger after writing the line it will skip the one with the condition, of course.

0
Tim Schmelter On

I would use File.ReadLines which is also "streaming" the lines under the hood, so not reading all lines at once. You could use LINQ to simplify it and return a custom class PerformanceStats:

public class PerformanceStats
{
    public string Timings{get; set;}
    public string Downloads{get; set;}
    public string Reset{get; set;}
}

void Main()
{
    PerformanceStats stats = GetPerformanceStats(@"\\host\c$\temp\logs\myPerformanceFile.txt");
}

static PerformanceStats GetPerformanceStats(string filePath)
{
    if(!System.IO.File.Exists(filePath))
    {
        return null;
    }
    
    StringComparison comparer = StringComparison.InvariantCultureIgnoreCase;
    string[] properties = {"Timings:", "Downloads:", "Reset:"};
    List<string> lines = System.IO.File.ReadLines(filePath)
        .SkipWhile(line => !line.Contains("Performance Stats:", comparer))
        .Take(20) // or 21 since it starts at the "Performance Stats"-line
        .Where(line => properties.Any(p => line.Contains(p, comparer)))
        .ToList();

    return new PerformanceStats
    {
        Timings = lines.FirstOrDefault(l => l.Contains("Timings:", comparer)),
        Downloads = lines.FirstOrDefault(l => l.Contains("Downloads:", comparer)),
        Reset = lines.FirstOrDefault(l => l.Contains("Reset:", comparer))
    };
}