我有一个日志文件,我想得到一些信息。我需要的信息在最后一行之前的行上,最后一行是/可能是空的。所以它实际上是最后一行之前的一行,如果最后一行是空的,则是最后一行之前的两行。
我知道如何使用以下方法到达文件的最后一行:
var lastLine = File.ReadLines("SomeFile.log").Last();我还可以使用Linq跳过使用.skipWhile()或.skip(1)的行,但不能后退。
我不知道怎样才能到达我需要的线路。这是日志文件最后几行的示例(最后一行为空白):
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)。
发布于 2021-06-02 16:23:03
也许您可以使用这个扩展方法:
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();
}
}用法:
var secondLastLine = File.ReadLines("SomeFile.log").GetLastItem(2);如果您不使用C#8,所以不能使用范围,范围,那么将return list[^countFromEnd]替换为return list[list.Count - countFromEnd]。
发布于 2021-06-02 16:24:17
File.ReadLines("SomeFile.log").Last();将遍历所有行并保留最后一行。对于大型文件来说,这是很昂贵的。至少它并不能把他们都留在记忆里。
一个更快的替代方法是读取最后的X字节,将它们转换为字符串并将其拆分为行。如果您有UTF8文件,这并不像听起来那么容易,因为块可能遗漏了第一个字符的第一个字节。这个问题问如何做到这一点。和UTF8是留给读者的摘录。
要检索IEnumerable<T>中的最后N项,可以使用.NET Core引入的TakeLast方法:
var lastLines = File.ReadLines("SomeFile.log").TakeLast(2);还有SkipLast,所以如果您想从最后一行获得第二行,您可以使用:
var secondLast = File.ReadLines("SomeFile.log").TakeLast(2).SkipLast(1);不过,只需一行,TakeLast(2).FirstOrDefault()就足够了。
对于.NET框架,您可以使用类似于这个答案的密码或这一个的东西来迭代并保持最后N行:
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(),方法是返回去排队的项,而不是丢弃它们:
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;
}
}
}发布于 2021-06-02 16:04:23
使用C#8的 距离算子
如果您已经有了内存中的数组,并且可以使用C# 8,则可以这样做:
var Lines = File.ReadAllLines("SomeFile.log");
var SecondToLast = Lines[^2];无C#8.
或者,正如Tim提到的,您可以在索引器上进行算术:
var Lines = File.ReadAllLines("SomeFile.log");
var SecondToLast = Lines[Lines.Length - 2];基于注释的编辑.从您的注释中,您似乎不太确定您将得到多少空行。如果是这样的话,您最好使用一种更通用的方法,例如:
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.
}在你的例子中,你会这样称呼它:
var FirstNotEmptyLine = FirstNotEmpty(Lines, BottomUp: true);还可以先发制人地从数组中删除空行:
var WithoutEmptyLines = Lines.Where(x => !string.IsNullOrWhiteSpace(x));然后“安全”得到最后一行。
https://stackoverflow.com/questions/67808404
复制相似问题