4

What is the most efficient way to read the last symbol or line of a large text file using C#?

tshepang
  • 12,111
  • 21
  • 91
  • 136
Ksice
  • 3,277
  • 9
  • 43
  • 67

6 Answers6

5

Assuming your text file is ASCII, this method will allow you to jump straight to the last character and avoid reading the rest of the file (like all the other answers given so far do).

using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read))
{
    stream.Seek(-1, SeekOrigin.End);
    byte b = (byte)stream.ReadByte();
    char c = (char)b;
}

If your program needs to handle multi-byte encodings, you might need to perform some complex logic, as shown is Skeet's answer. However, given that your case is restricted just to reading the last character, you can implement a simplified version specific to your expected encoding. The code below works for UTF-8 (which is the most popular encoding today). The Seek may land your reader in the middle of a preceding character, but the decoder will recover from this by the time it reads the last character.

FileInfo fileInfo = new FileInfo(path);
int maxBytesPerChar = Encoding.UTF8.GetMaxByteCount(1);
int readLength = Math.Min(maxBytesPerChar, (int)fileInfo.Length);

using (StreamReader reader = new StreamReader(path, Encoding.UTF8))
{
    reader.DiscardBufferedData();
    reader.BaseStream.Seek(-readLength, SeekOrigin.End);

    string s = reader.ReadToEnd();
    char c = s.Last();
}
Community
  • 1
  • 1
Douglas
  • 53,759
  • 13
  • 140
  • 188
  • This looks interesting. +1. How does this work 'under the hood'? Surely it would have to read the entirety of the file in some sort of fashion first to know 'where' the last byte is? –  Oct 07 '13 at 08:23
  • @DeeMac There is not really any "under the hood". It uses ".Seek()" which maps to the Windows API function [`SetFilePointer()`](http://msdn.microsoft.com/en-us/library/windows/desktop/aa365541%28v=vs.85%29.aspx) – Matthew Watson Oct 07 '13 at 08:28
  • @DeeMac: No. The operating system records the file length, so it wouldn't need to be traversed each time it is read. – Douglas Oct 07 '13 at 08:29
  • Understood. Will keep this in mind. Thanks. –  Oct 07 '13 at 08:29
4

If the file is not too large, just read the lines and pick the last:

string lastLine = File.ReadLines("pathToFile").LastOrDefault(); // if the file is empty

So you get the last character in this way:

Char lastChar = '\0';
if(lastLine  != null) lastChar = lastLine.LastOrDefault();

File.ReadLines does not need to read all lines before it can start processsing, so it's cheap in terms of memory consumption.

Here is the more complicated way from J. Skeet: How to read a text file reversely with iterator in C#

Community
  • 1
  • 1
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
0
string s = File.ReadAllText("test.txt");
string[] split = s.Split(s[s.Length - 1]);

and for last line :-

var lastLine = File.ReadLines("test.txt").Last();
Neel
  • 11,625
  • 3
  • 43
  • 61
0
using System;
using System.IO;

class Test
{
    public static void Main()
    {
        try
        {
            using (StreamReader sr = new StreamReader("TestFile.txt"))
            {
                String line = sr.ReadToEnd();
                Console.WriteLine(line[line.length-1);
            }
        }
        catch (Exception e)
        {
            Console.WriteLine("The file could not be read:");
            Console.WriteLine(e.Message);
        }
    }
}
0

I'd suggest to use the ReadToEnd-Method of the File-Class, so you don't need to close the Steam/TextReader:

string s = File.ReadAllText(@"YOUR PATH HERE");
char lastchar = s[s.Length - 1];
jAC
  • 5,195
  • 6
  • 40
  • 55
-1

Fastes method:

var lines = new ReverseLineReader(filename);
var last = lines.Take(1);

You can read more Here

Community
  • 1
  • 1
Norbert Pisz
  • 3,392
  • 3
  • 27
  • 42