4

Currently I'm reading file content using File.ReadAllText(), but now I need to read last x lines in my txt file. How can I do that?

content of myfile.txt

line1content 
line2content
line3content
line4content 

string contentOfLastTwoLines = ...
user1765862
  • 13,635
  • 28
  • 115
  • 220

6 Answers6

10

What about this

List <string> text = File.ReadLines("file.txt").Reverse().Take(2).ToList()
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
Sachin
  • 40,216
  • 7
  • 90
  • 102
  • 6
    +1, but it does also reverse the order of the last two lines. You need another `Reverse()` after the `Take(2)` to fix that. – Blorgbeard Apr 07 '13 at 21:17
  • 1
    As in Blorgbeards answer: Whole file content is unnecessary read into memory :) – MarcinJuraszek Apr 07 '13 at 21:18
  • @Blorgbeard: Only if the order matters. Even if `ReadLines` streams, `Reverse` needs to create a buffer from all lines in the file to reverse the order. So it's basically the same as `ReadAllLIines` but more readable(imho). – Tim Schmelter Apr 07 '13 at 21:19
  • @Blorgbeard but `Reverse` has to read all elements from source collection, to return reversed one! So it's really like `ReadAllLines` in that situation. Check [eduLinq: Reverse](http://msmvps.com/blogs/jon_skeet/archive/2011/01/08/reimplementing-linq-to-objects-part-27-reverse.aspx) blog post by John Skeet. – MarcinJuraszek Apr 07 '13 at 21:20
  • @MarcinJuraszek yeah I just realised that :P – Blorgbeard Apr 07 '13 at 21:21
  • See my answer in the duplicate http://stackoverflow.com/a/33907602/4821032 – Xan-Kun Clark-Davis Nov 25 '15 at 02:42
6

Use Queue<string> to store last X lines and replace the first one with currently read:

int x = 4;   // number of lines you want to get

var buffor = new Queue<string>(x);

var file = new StreamReader("Input.txt");

while (!file.EndOfStream)
{
    string line = file.ReadLine();

    if (buffor.Count >= x)
        buffor.Dequeue();
    buffor.Enqueue(line);
}

string[] lastLines = buffor.ToArray();

string contentOfLastLines = String.Join(Environment.NewLine, lastLines);
MarcinJuraszek
  • 124,003
  • 15
  • 196
  • 263
4

You can use ReadLines to avoid reading the entire file into memory, like this:

const int neededLines = 5;
var lines = new List<String>();
foreach (var s in File.ReadLines("c:\\myfile.txt")) {
    lines.Add(s);
    if (lines.Count > neededLines) {
        lines.RemoveAt(0);
    }
}

Once the for loop is finished, the lines list contains up to the last neededLines of text from the file. Of course if the file does not contain as many lines as required, fewer lines will be placed in the lines list.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
3

Read the lines into an array, then extract the last two:

string[] lines = File.ReadAllLines();
string last2 = lines[lines.Count-2] + Environment.NewLine + lines[lines.Count-1];

Assuming your file is reasonably small, it's easier to just read the whole thing and throw away what you don't need.

Blorgbeard
  • 101,031
  • 48
  • 228
  • 272
  • 4
    Whole file content is unnecessary read into memory . – MarcinJuraszek Apr 07 '13 at 21:05
  • OP is currently reading the whole file anyway. And assuming it's a small file and not in a performance critical loop, this is much easier. You pretty much have to read the whole file to get the last two lines anyway. – Blorgbeard Apr 07 '13 at 21:06
  • Yes, but you don't have to store all lines in memory to get just `X` last. – MarcinJuraszek Apr 07 '13 at 21:09
  • If you're talking about 500MB log files, then sure. But otherwise, who cares? RAM is cheap and storing a 500KB text file for a second while you extract some data is not worth extra time spent optimizing. – Blorgbeard Apr 07 '13 at 21:11
0

Since reading a file is done linearly, usually line-by-line. Simply read line-by-line and remember last two lines (you can use queue or something if you want... or just two string variables). When you get to EOF, you'll have your last two lines.

Stonehead
  • 366
  • 2
  • 12
0

You want to read the file backwards using ReverseLineReader:

How to read a text file reversely with iterator in C#

Then run .Take(2) on it. var lines = new ReverseLineReader(filename); var last = lines.Take(2);

OR

Use a System.IO.StreamReader.

string line1, line2;

using(StreamReader reader = new StreamReader("myFile.txt")) {
    line1 = reader.ReadLine();
    line2 = reader.ReadLine();
}
Abdelrahman Wahdan
  • 2,056
  • 4
  • 36
  • 43