【问题标题】:Reading the 2 last line from a text从文本中读取最后 2 行
【发布时间】:2017-04-03 13:23:45
【问题描述】:

我是 的新手,我正在开发一个应用程序,该应用程序在文本文件的最后两行显示两个日期的时差。

我想从文件文本中读取最后一行,我已经知道如何读取最后一行,但我需要阅读最后一行。

这是我的代码:

var lastLine = File.ReadAllLines("C:\\test.log").Last();
                richTextBox1.Text = lastLine.ToString();

【问题讨论】:

    标签: c# c#


    【解决方案1】:

    自从

     File.ReadAllLines("C:\\test.log");
    

    返回一个数组你可以取数组的最后两项:

     var data = File.ReadAllLines("C:\\test.log");
    
     string last = data[data.Length - 1];
     string lastButOne = data[data.Length - 2];
    

    general 的情况下 long 文件(这就是为什么ReadAllLines 是一个糟糕的选择)你可以实现

    public static partial class EnumerableExtensions {
      public static IEnumerable<T> Tail<T>(this IEnumerable<T> source, int count) {
        if (null == source)
          throw new ArgumentNullException("source");
        else if (count < 0)
          throw new ArgumentOutOfRangeException("count");
        else if (0 == count)
          yield break;
    
        Queue<T> queue = new Queue<T>(count + 1);
    
        foreach (var item in source) {
          queue.Enqueue(item);
    
          if (queue.Count > count)
            queue.Dequeue();
        }
    
        foreach (var item in queue)
          yield return item;
      }
    }
    

    ...

    var lastTwolines = File
      .ReadLines("C:\\test.log") // Not all lines
      .Tail(2);
    

    【讨论】:

      【解决方案2】:

      在返回请求的最后几行之前,所有先前的答案都会急切地将所有文件加载到内存中。如果文件很大,这可能是一个问题。幸运的是,这很容易避免。

      public static IEnumerable<string> ReadLastLines(string path, int count)
      {
          if (count < 1)
              return Enumerable.Empty<string>();
      
          var queue = new Queue<string>(count);
      
          foreach (var line in File.ReadLines(path))
          {
              if (queue.Count == count)
                  queue.Dequeue();
      
               queue.Enqueue(line);
          }
      
          return queue;
      }
      

      这只会在内存中保留最后的n 读取行,避免大文件的内存问题。

      【讨论】:

      • 您仍然必须遍历所有行,这对于大文件来说效率很低。请参阅我的答案中的链接问题。
      • @Staeff 当然是的,但是它比实际将整个文件加载到内存中效率高出几个数量级,这是基于ReadAllLines 的其他解决方案所做的。
      • @InBetween 但仍然使用StreamReader 会更有效,正如我在回答中所说的那样。当您只需要最后 2 行时,加载整个文件是没有意义的。
      • @m.rogalski 我在哪里加载整个文件? ReadLines 生成一个IEnumerable&lt;string&gt;,只要文件中有下一行,它就会简单地吐出下一行。无论如何,您的解决方案和我的解决方案是相同的,抱歉我没有阅读过去的 StreamReader 因为它没有必要,ReadLines 也可以。
      • @InBetween 我的错。我虽然在其他答案中是ReadAllLines
      【解决方案3】:

      你可以试试这个

      var lastLines = File.ReadAllLines("C:\\test.log").Reverse().Take(2).Reverse();
      

      但是根据文件的大小,可能有比一次读取所有行更有效的方法来处理它。见Get last 10 lines of very large text file > 10GBHow to read last “n” lines of log file

      【讨论】:

      • 反转while文件,取两个元素再反转一次?对我来说似乎很奇怪,但应该可以。
      • 第二个反转只有在您关心行的顺序时才需要,从她的问题描述中猜测这可能没有必要,但只是为了给出完整的答案,我将其包含在内。
      【解决方案4】:

      只需将ReadAllLines 的结果存储到一个变量中,然后取最后两个:

      var allText = File.ReadAllLines("C:\\test.log");
      var lastLines = allText.Skip(allText.Length - 2);
      

      【讨论】:

        【解决方案5】:

        你可以使用Skip()Take()like

        var lastLine = File.ReadAllLines("C:\\test.log");
        var data = lastLine.Skip(lastLine.Length - 2);
                        richTextBox1.Text = lastLine.ToString();
        

        【讨论】:

        • 您的Take 是多余的,因为跳过后您知道您只剩下 2 件物品了。
        【解决方案6】:

        您可以将StreamReaderQueue&lt;string&gt; 结合使用,因为您必须以任何一种方式读取整个文件。

        // if you want to read more lines change this to the ammount of lines you want
        const int LINES_KEPT = 2;
        
        Queue<string> meQueue = new Queue<string>();
        using ( StreamReader reader = new StreamReader(File.OpenRead("C:\\test.log")) )
        {
            string line = string.Empty;
            while ( ( line = reader.ReadLine() ) != null )
            {
                if ( meQueue.Count == LINES_KEPT  )
                   meQueue.Dequeue();
        
                meQueue.Enqueue(line);
            }
        }
        

        现在你可以像这样使用这两行:

        string line1 = meQueue.Dequeue(); 
        string line2 = meQueue.Dequeue(); // <-- this is the last line.
        

        或将其添加到RichTextBox

        richTextBox1.Text = string.Empty; // clear the text
        while ( meQueue.Count != 0 )
        {
            richTextBox1.Text += meQueue.Dequeue(); // add all lines in the same order as they were in file
        }
        

        使用File.ReadAllLines 将阅读整个文本,然后使用Linq 将遍历已经红线。此方法一次完成所有操作。

        【讨论】:

          【解决方案7】:
          string line;
          string[] lines = new string[]{"",""};
          int index = 0;
          using ( StreamReader reader = new StreamReader(File.OpenRead("C:\\test.log")) )
          {
             while ( ( line = reader.ReadLine() ) != null )
             {
                 lines[index] = line;
                 index = 1-index;
             }
          }
          // Last Line -1 = lines[index]
          // Last line    = lines[1-index]
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-07-26
            • 1970-01-01
            • 2012-07-22
            • 2022-11-02
            • 2015-09-07
            • 2019-05-26
            • 1970-01-01
            相关资源
            最近更新 更多