从“尾”到“尾”捕捉标准
本文关键字:标准 | 更新日期: 2023-09-27 18:02:56
我试图在follow模式下捕获tail的输出,它在检测到文件长度的变化时输出文本-这对于在添加行时跟踪日志文件特别有用。由于某种原因,我对StandardOutput.Read()的调用阻塞了,直到tail.exe完全退出。
相关代码示例:var p = new Process() {
StartInfo = new ProcessStartInfo("tail.exe") {
UseShellExecute = false,
RedirectStandardOutput = true,
Arguments = "-f c:''test.log"
}
};
p.Start();
// the following thread blocks until the process exits
Task.Factory.StartNew(() => p.StandardOutput.Read());
// main thread wait until child process exits
p.WaitForExit();
我还尝试使用对OutputDataReceived
事件处理程序的支持,它显示相同的阻塞行为:
p.OutputDataReceived += (proc, data) => {
if (data != null && data.Data != null) {
Console.WriteLine(data.Data);
}
};
p.BeginOutputReadLine();
我确实在StandardOutput.Read()调用周围多了一点代码,但这简化了示例,并且仍然显示出不希望看到的阻塞行为。我还可以做些什么来允许我的代码在子应用程序退出之前对StandardOutput流中的数据可用性做出反应?
这是否只是tail.exe运行的一个怪癖?我使用的是作为UnxUtils包的一部分编译的2.0版本。
Update:这似乎至少部分与tail.exe中的怪癖有关。我从GnuWin32项目中获取了二进制文件,作为coretils包的一部分,版本升级到5.3.0。如果我使用-f
选项跟随而不重试,我就会在STDERR上得到可怕的"错误的文件描述符"问题(很容易忽略),并且进程立即终止。如果我使用-F
选项包括重试,它似乎工作正常后,坏的文件描述符消息已经通过,它试图打开文件第二次。
是否有一个最近的win32构建从coretils git仓库我可以尝试?
我知道这不是你想要的,但正如James在评论中所说的,你可以直接在c#中实现等效的功能,以节省你启动另一个进程的时间。
你可以这样做:
using System;
using System.IO;
using System.Text;
using System.Threading;
public class FollowingTail : IDisposable
{
private readonly Stream _fileStream;
private readonly Timer _timer;
public FollowingTail(FileInfo file,
Encoding encoding,
Action<string> fileChanged)
{
_fileStream = new FileStream(file.FullName,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite);
_timer = new Timer(o => CheckForUpdate(encoding, fileChanged),
null,
0,
500);
}
private void CheckForUpdate(Encoding encoding,
Action<string> fileChanged)
{
// Read the tail of the file off
var tail = new StringBuilder();
int read;
var b = new byte[1024];
while ((read = _fileStream.Read(b, 0, b.Length)) > 0)
{
tail.Append(encoding.GetString(b, 0, read));
}
// If we have anything notify the fileChanged callback
// If we do not, make sure we are at the end
if (tail.Length > 0)
{
fileChanged(tail.ToString());
}
else
{
_fileStream.Seek(0, SeekOrigin.End);
}
}
// Not the best implementation if IDisposable but you get the idea
// See http://msdn.microsoft.com/en-us/library/ms244737(v=vs.80).aspx
// for how to do it properly
public void Dispose()
{
_timer.Dispose();
_fileStream.Dispose();
}
}
然后调用,例如:
new FollowingTail(new FileInfo(@"C:'test.log"),
Encoding.ASCII,
s =>
{
// Do something with the new stuff here, e.g. print it
Console.Write(s);
});