我有一个非常大的日志文件。我需要找出最后一个" WARN"有效地在该文件中划线(即:从末尾读取),解析它,并将其作为对象返回"日期"字段(日期时间类型),"级别"字段和"描述"字段
有什么建议吗?
这是文件的样子
[Mon Dec 14 14:57:53 2015] [notice] Child 6180: Acquired the start mutex.
[Mon Dec 14 14:57:53 2015] [notice] Child 6180: Starting 150 worker threads.
[Mon Dec 14 15:04:43 2015] [warn] pid file C:/Program Files (x86)/Citrix/XTE/logs/xte.pid overwritten -- Unclean shutdown of previous Apache run?
[Mon Dec 14 15:04:43 2015] [notice] Server built: May 27 2011 16:04:42
[Mon Dec 14 15:04:43 2015] [notice] Parent: Created child process 5608
编辑:此命令必须查看文件内部,按搜索条件查找最后一个匹配行,返回该行,然后"停止"。可能的重复问题在很多方面都有所不同:我的脚本不能简单地坐在那里等待线出现 - 它需要运行,尽快获得线路,然后离开。此外,它需要通过子字符串搜索它,最后它需要返回一个DateTime和其他分解的字段。谢谢你没有投票来结束这个问题。
答案 0 :(得分:0)
以原始Stream
打开文件,从末尾寻找“体面”的块大小(比如1 MB),然后在结果字节中搜索“warn”的二进制表示,直到找到最后一个实例(我假设您事先知道编码)。如果找到它,请扫描行终止符。如果找不到,请找回1 + 1 MB然后再去。重复,直到你开始寻找。
如果整个文件中没有“警告”,这将比按顺序读取文件慢,但是如果你确定你想要的那一行接近结尾,这可以很快终止。要做的重要事情是不将文件作为带有StreamReader
的文本读取,因为您失去了任意搜索的能力。
实际上,正确地获取这个想法的代码更为复杂。这个操作的难度不是由于PowerShell中的任何东西 - 在任何语言中都没有简单的方法可以做到这一点,因为在我知道的任何文件系统中,反向读取文件并不是一种有效的操作。
答案 1 :(得分:0)
我这样接近:
ParentPicture
答案 2 :(得分:-1)
这肯定不会有效率。 PowerShell和C#(以及其他所有内容)中的所有内容都是围绕阅读前进而非后退而构建的。考虑到这一点以及您甚至不知道最后一行的位置这一事实,除非您想花几个小时编写自己的ReverseStreamReader,否则我认为没有办法避免处理整个文件。
假设文件大于RAM - 这使得Get-Content
不切实际,IMO - 我可能会做类似的事情:
$LineNumber = [uint64]0;
$StreamReader = New-Object System.IO.StreamReader -ArgumentList "C:\LogFile.log"
$SearchPattern = [Regex]::Escape('[warn]');
while ($Line = $StreamReader.ReadLine()) {
$LineNumber++;
if ($Line -match $SearchPattern) {
$LastLineNumber = $LineNumber;
$LastLineMatch = $Line;
}
}
$StreamReader.Close()
$LastLineNumber
$LastLineMatch
解析该行可能涉及很多String.IndexOf()和String.Substring()。将日期转换为DateTime应该这样完成:
[datetime]::ParseExact('Mon Dec 14 15:04:43 2015','ddd MMM dd HH:mm:ss yyyy',[System.Globalization.CultureInfo]::InvariantCulture,[System.Globalization.DateTimeStyles]::None);
我选择-match
超过-like
,因为据我所知,它实际上表现更好。那可能只是我的系统。