我想定期读取也正在写入的日志文件。 该程序将定期读取日志文件内容并解析它以提取一些值。但我不想每次都阅读整个文件。
有没有办法从特定的行开始读取文件?
例如,在第一次读取时,文件有100行。我注意到这个值,下次我读到时我开始从第100行开始读取并存储当前文件的行号。
有一种有效的方法吗? 日志文件将增长到大约100MB,我需要每5秒阅读一次。因此,每次读取完整文件效率都不高。
非常感谢任何建议。
答案 0 :(得分:5)
我认为你正在寻找这个,其中偏移将是你想要回溯多少。参考:MSDN
using (FileStream fs = new FileStream(filepath, FileMode.Open, FileAccess.Read))
{
fs.Seek(offset, SeekOrigin.End);
}
现在文件流指向远离你设置'offset'的文件,你可以从那里读取。
答案 1 :(得分:2)
如果仅附加日志,则可以尝试在没有锁定的情况下以只读模式打开文件。这样,其他进程可以在您阅读时写入它。
var fs = new FileStream(path,FileMode.Open,FileAccess.Read, FileShare.ReadWrite);
答案 2 :(得分:2)
对于快速和肮脏的东西,我使用它。在这种情况下它是一个日志转储 - 我真的不关心我得到多少行,我只想在最后(numBytes
):
cmdLogReader = new System.IO.StreamReader(cmdLogFileIn);
if (cmdLogReader.BaseStream.Length < (numBytes - 1)) {
return cmdLogReader.ReadToEnd;
} else {
cmdLogReader.BaseStream.Seek(-numBytes, System.IO.SeekOrigin.End);
cmdLogReader.ReadLine();
return cmdLogReader.ReadToEnd;
}
你总是可以在开头保存BaseStream.Length
并使用它来计算下一次返回的距离(即:numBytes
变为BaseStream.Length - previousBaseStreamLength
或其他),这会让顺序调用抓取自上次读取以来添加的任何内容。
如果您这样做,可能必须跳过ReadLine
来电,因为它实际上只是在回溯随机数量后向上移动到最近的一行。如果您知道自己要在线路边界上着陆,那么您可以ReadToEnd
。
这是一个坚韧不拔的实现,但它的速度非常快,这就是我使用它的原因。
答案 3 :(得分:2)
Seek可以做得很好。但我想提供其他方法。
public static void Read()
{
var fs = new FileStream(@"G:\test.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
int lastReadCount = 0;
while (true)
{
var totalCountOfFile = fs.Length;
if (lastReadCount < totalCountOfFile)
{
var buffer = new byte[1024];
int count = fs.Read(buffer, 0, buffer.Length);
lastReadCount += count;
Display(buffer);
}
Thread.Sleep(5000);
}
}
private static void Display(byte[] buffer)
{
var text = Encoding.UTF8.GetString(buffer.Where(p=>p != 0).ToArray());
Console.Write(text);
}