How to read last “n” lines of log file

前端 未结 7 1095
轮回少年
轮回少年 2020-12-03 14:24

need a snippet of code which would read out last \"n lines\" of a log file. I came up with the following code from the net.I am kinda new to C sharp. Since the log file migh

相关标签:
7条回答
  • 2020-12-03 14:44

    This is in no way optimal but for quick and dirty checks with small log files I've been using something like this:

    List<string> mostRecentLines = File.ReadLines(filePath)
        // .Where(....)
        // .Distinct()
        .Reverse()
        .Take(10)
        .ToList()
    
    0 讨论(0)
  • 2020-12-03 14:47

    Something that you can now do very easily in C# 4.0 (and with just a tiny bit of effort in earlier versions) is use memory mapped files for this type of operation. Its ideal for large files because you can map just a portion of the file, then access it as virtual memory.

    There is a good example here.

    0 讨论(0)
  • 2020-12-03 14:52

    Your code will perform very poorly, since you aren't allowing any caching to happen.
    In addition, it will not work at all for Unicode.

    I wrote the following implementation:

    ///<summary>Returns the end of a text reader.</summary>
    ///<param name="reader">The reader to read from.</param>
    ///<param name="lineCount">The number of lines to return.</param>
    ///<returns>The last lneCount lines from the reader.</returns>
    public static string[] Tail(this TextReader reader, int lineCount) {
        var buffer = new List<string>(lineCount);
        string line;
        for (int i = 0; i < lineCount; i++) {
            line = reader.ReadLine();
            if (line == null) return buffer.ToArray();
            buffer.Add(line);
        }
    
        int lastLine = lineCount - 1;           //The index of the last line read from the buffer.  Everything > this index was read earlier than everything <= this indes
    
        while (null != (line = reader.ReadLine())) {
            lastLine++;
            if (lastLine == lineCount) lastLine = 0;
            buffer[lastLine] = line;
        }
    
        if (lastLine == lineCount - 1) return buffer.ToArray();
        var retVal = new string[lineCount];
        buffer.CopyTo(lastLine + 1, retVal, 0, lineCount - lastLine - 1);
        buffer.CopyTo(0, retVal, lineCount - lastLine - 1, lastLine + 1);
        return retVal;
    }
    
    0 讨论(0)
  • 2020-12-03 14:53

    Does your log have lines of similar length? If yes, then you can calculate average length of the line, then do the following:

    1. seek to end_of_file - lines_needed*avg_line_length (previous_point)
    2. read everything up to the end
    3. if you grabbed enough lines, that's fine. If no, seek to previous_point - lines_needed*avg_line_length
    4. read everything up to previous_point
    5. goto 3

    memory-mapped file is also a good method -- map the tail of file, calculate lines, map the previous block, calculate lines etc. until you get the number of lines needed

    0 讨论(0)
  • 2020-12-03 14:59

    Had trouble with your code. This is my version. Since its' a log file, something might be writing to it, so it's best making sure you're not locking it.

    You go to the end. Start reading backwards until you reach n lines. Then read everything from there on.

            int n = 5; //or any arbitrary number
            int count = 0;
            string content;
            byte[] buffer = new byte[1];
    
            using (FileStream fs = new FileStream("text.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                // read to the end.
                fs.Seek(0, SeekOrigin.End);
    
                // read backwards 'n' lines
                while (count < n)
                {
                    fs.Seek(-1, SeekOrigin.Current);
                    fs.Read(buffer, 0, 1);
                    if (buffer[0] == '\n')
                    {
                        count++;
                    }
    
                    fs.Seek(-1, SeekOrigin.Current); // fs.Read(...) advances the position, so we need to go back again
                }
                fs.Seek(1, SeekOrigin.Current); // go past the last '\n'
    
                // read the last n lines
                using (StreamReader sr = new StreamReader(fs))
                {
                    content = sr.ReadToEnd();
                }
            }
    
    0 讨论(0)
  • 2020-12-03 15:05

    A friend of mine uses this method (BackwardReader can be found here):

    public static IList<string> GetLogTail(string logname, string numrows)
    {
        int lineCnt = 1;
        List<string> lines = new List<string>();
        int maxLines;
    
        if (!int.TryParse(numrows, out maxLines))
        {
            maxLines = 100;
        }
    
        string logFile = HttpContext.Current.Server.MapPath("~/" + logname);
    
        BackwardReader br = new BackwardReader(logFile);
        while (!br.SOF)
        {
            string line = br.Readline();
            lines.Add(line + System.Environment.NewLine);
            if (lineCnt == maxLines) break;
            lineCnt++;
        }
        lines.Reverse();
        return lines;
    }
    
    0 讨论(0)
提交回复
热议问题