首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在文本文件的最后一行之前读取两行

在文本文件的最后一行之前读取两行
EN

Stack Overflow用户
提问于 2021-06-02 15:46:35
回答 4查看 506关注 0票数 1

我有一个日志文件,我想得到一些信息。我需要的信息在最后一行之前的行上,最后一行是/可能是空的。所以它实际上是最后一行之前的一行,如果最后一行是空的,则是最后一行之前的两行。

我知道如何使用以下方法到达文件的最后一行:

代码语言:javascript
复制
var lastLine = File.ReadLines("SomeFile.log").Last();

我还可以使用Linq跳过使用.skipWhile()或.skip(1)的行,但不能后退。

我不知道怎样才能到达我需要的线路。这是日志文件最后几行的示例(最后一行为空白):

代码语言:javascript
复制
2021/05/02 23:47:57:008989 send_status_message(2) Info: "Stream status heartbeat sent: [SY  1.3.2       ]"
2021/05/02 23:47:57:225172 send_status_message(2) Info: "Received heartbeat response: [S               ]"
2021/05/03 00:00:00:045055 set_log_dir(2) Info: "Changing log directory to /abc/def/logs/2021-05-03."
<blank-line>    

我正试图在这一行上得到时间戳(即2021/05/02 23:47:57:225172)。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2021-06-02 16:23:03

也许您可以使用这个扩展方法:

代码语言:javascript
复制
public static class EnumerableExtensions
{
    public static T GetLastItem<T>(this IEnumerable<T> seq, int countFromEnd)
    {
        if(seq is IList<T> list) return list[^countFromEnd];
        using var enumerator = seq.Reverse().GetEnumerator();
        while(enumerator.MoveNext())
        {
            if(--countFromEnd == 0) return enumerator.Current;
        }
        throw new ArgumentOutOfRangeException();
    }
}

用法:

代码语言:javascript
复制
var secondLastLine = File.ReadLines("SomeFile.log").GetLastItem(2);

如果您不使用C#8,所以不能使用范围,范围,那么将return list[^countFromEnd]替换为return list[list.Count - countFromEnd]

票数 0
EN

Stack Overflow用户

发布于 2021-06-02 16:24:17

File.ReadLines("SomeFile.log").Last();将遍历所有行并保留最后一行。对于大型文件来说,这是很昂贵的。至少它并不能把他们都留在记忆里。

一个更快的替代方法是读取最后的X字节,将它们转换为字符串并将其拆分为行。如果您有UTF8文件,这并不像听起来那么容易,因为块可能遗漏了第一个字符的第一个字节。这个问题问如何做到这一点。和UTF8是留给读者的摘录。

要检索IEnumerable<T>中的最后N项,可以使用.NET Core引入的TakeLast方法:

代码语言:javascript
复制
var lastLines = File.ReadLines("SomeFile.log").TakeLast(2);

还有SkipLast,所以如果您想从最后一行获得第二行,您可以使用:

代码语言:javascript
复制
var secondLast = File.ReadLines("SomeFile.log").TakeLast(2).SkipLast(1);

不过,只需一行,TakeLast(2).FirstOrDefault()就足够了。

对于.NET框架,您可以使用类似于这个答案的密码这一个的东西来迭代并保持最后N行:

代码语言:javascript
复制
public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> source, int count)
{
    if (source == null) { throw new ArgumentNullException("source"); }

    Queue<T> lastElements = new Queue<T>();
    foreach (T element in source)
    {
        lastElements.Enqueue(element);
        if (lastElements.Count > count)
        {
            lastElements.Dequeue();
        }
    }

    return lastElements;
}

这段代码需要稍加修改才能成为一个SkipLast(),方法是返回去排队的项,而不是丢弃它们:

代码语言:javascript
复制
public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source, int count)
{
    if (source == null) { throw new ArgumentNullException("source"); }

    Queue<T> lastElements = new Queue<T>();
    foreach (T element in source)
    {
        lastElements.Enqueue(element);
        if (lastElements.Count > count)
        {
            var head=lastElements.Dequeue();
            yield return head;
        }
    }
}
票数 3
EN

Stack Overflow用户

发布于 2021-06-02 16:04:23

使用C#8的 距离算子

如果您已经有了内存中的数组,并且可以使用C# 8,则可以这样做:

代码语言:javascript
复制
var Lines = File.ReadAllLines("SomeFile.log");
var SecondToLast = Lines[^2];

无C#8.

或者,正如Tim提到的,您可以在索引器上进行算术:

代码语言:javascript
复制
var Lines = File.ReadAllLines("SomeFile.log");
var SecondToLast = Lines[Lines.Length - 2];

基于注释的编辑.从您的注释中,您似乎不太确定您将得到多少空行。如果是这样的话,您最好使用一种更通用的方法,例如:

代码语言:javascript
复制
    static string FirstNotEmpty(string[] Lines, bool BottomUp = false)
    {
        if (BottomUp)
        {
            for (int i = Lines.Length - 1; i >= 0; i--)
            {
                var CurrentLine = Lines[i];
                if (!string.IsNullOrWhiteSpace(CurrentLine))
                    return CurrentLine;
            }
        }
        else
        {
            for (int i = 0; i <= Lines.Length-1; i++)
            {
                var CurrentLine = Lines[i];
                if (!string.IsNullOrWhiteSpace(CurrentLine))
                    return CurrentLine;
            }
        }
        return null; //Or something else.
    }

在你的例子中,你会这样称呼它:

代码语言:javascript
复制
var FirstNotEmptyLine = FirstNotEmpty(Lines, BottomUp: true);

还可以先发制人地从数组中删除空行:

代码语言:javascript
复制
var WithoutEmptyLines = Lines.Where(x => !string.IsNullOrWhiteSpace(x));

然后“安全”得到最后一行。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67808404

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档