我如何用我自己的c#应用程序捕获、记录和显示任意进程的控制台输出
本文关键字:任意 显示 进程 输出 控制台 记录 自己的 何用我 应用程序 | 更新日期: 2023-09-27 18:11:11
我想在c#程序上运行一个特定的运行文件,并在此过程中在屏幕上显示输出并将其保存在文件中。
我不希望将输出保存在文件中,然后在屏幕上显示。
我希望这两件事同时发生。
我知道用"tee"来做这件事的方法,但每次我都失败了。
谁能给我一个例子(有效)使用"tee"?
主要问题是,您是否能够控制希望记录和显示其输出的程序的源代码?
如果是,那么您有几个选择。可能最简单的方法是使用复合textwwriter"劫持"控制台的输出流:
public class CompoundWriter:TextWriter
{
public readonly List<TextWriter> Writers = new List<TextWriter>();
public override void WriteLine(string line)
{
if(Writers.Any())
foreach(var writer in Writers)
writer.WriteLine(line);
}
//override other TextWriter methods as necessary
}
...
//When the program starts, get the default Console output stream
var consoleOut = Console.Out;
//Then replace it with a Compound writer set up with a file writer and the normal Console out.
var compoundWriter = new CompoundWriter();
compoundWriter.Writers.Add(consoleOut);
compoundWriter.Writers.Add(new TextWriter("c:'temp'myLogFile.txt");
Console.SetOut(compoundWriter);
//From now on, any calls to Console's Write methods will go to your CompoundWriter,
//which will send them to the console and the file.
您还可以使用Trace侦听器来处理您想要输出到两个位置的任何输出:
Trace.Listeners.Clear();
Trace.Listeners.Add(new TextWriterTraceListener(Console.Out));
Trace.Listeners.Add(new TextWriterTraceListener(File.Open("C:'temp'myLogFile.txt");
//replace any call to Console.WriteLine() with Trace.WriteLine()
如果你无法控制你想要"tee"的控制台应用程序的源代码,并且控制台应用程序在执行过程中不需要任何输入,那么你可以使用命名管道来获取应用程序的输出并将其重定向。
var appLocation = @"C:'temp'myApp.exe";
var pipeName = "ConsoleNamedPipe";
using(var namedPipe = new NamedPipeServerStream(pipeName, PipeDirection.In))
{
var info = new ProcessStartInfo
{
FileName = "cmd.exe",
Arguments = String.Format(@"/C {1} >>''.'pipe'{0}",
pipeName, appLocation),
WindowStyle = ProcessWindowStyle.Hidden
};
ConsoleProcess = Process.Start(info);
pipe.WaitForConnection();
using (var reader = new StreamReader(pipe))
{
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
Console.WriteLine(line);
myFileWriter.WriteLine(line);
}
}
}
这是一个非常简单的例子;您可以通过使用双向管道提供更多的交互,但这将需要在您的端编写更多的代码。
您可以尝试以下操作:
C:'you_csharp_program.exe arg1 arg2 arg3 |tee filename
我不打算写出具体的代码示例,但我会告诉你,你可以看看日志框架,比如log4net,它有控制台和文件appender,可以做你想做的事情。你不能在你的代码日志中错误的记录语句。调试("一些消息")设置log4net配置,使用任意数量的appender,并让它一次将消息写入所有源,例如screen, file, db和email。
我似乎错过了问题的最后一句话,所以我的回答可能无效。
详细说明keith的回答,这是一个工作实现。它应该适用于所有的Write/WriteLine调用,而不必覆盖每个重载,因为当前(4.0,我假设更早)的textwwriter实现通过Write(char)
指导所有写。
public class TeeTextWriter : TextWriter
{
readonly TextWriter[] _redirectTo;
public override Encoding Encoding { get { return Encoding.UTF8; } }
public TeeTextWriter(params TextWriter[] redirectTo)
{
_redirectTo = redirectTo ?? new TextWriter[0];
}
public override void Write(char value)
{
foreach (var textWriter in _redirectTo)
{
textWriter.Write(value);
}
}
}
用法:
var realConsoleStream = Console.Out;
using (var fileOut = new StreamWriter(outFileName, false))
{
Console.SetOut(new TeeTextWriter(fileOut, realConsoleStream));
try
{
Console.WriteLine("Test");
}
finally
{
Console.SetOut(realConsoleStream);
}
}