Как я могу записывать, регистрировать и отображать вывод консоли любого произвольного процесса с моим собственным приложением c #? - PullRequest
1 голос
/ 11 октября 2011

Я хочу запустить в программе на C # определенный запущенный файл и во время него отобразить вывод на экране, а также сохранить его в файле.

Я не хочу, чтобы сохранил вывод в файле и позже отобразил его на экране.

Я хочу, чтобы они оба произошли вместе.

Я знаю способ сделать это "ти", но я терпел неудачу каждый раз, когда пытался это сделать.

Может ли кто-нибудь дать мне пример (который работает), используя "тройник"?

Ответы [ 4 ]

2 голосов
/ 11 октября 2011

Главный вопрос заключается в том, имеете ли вы контроль над исходным кодом программы, чей вывод вы хотите зарегистрировать и отобразить?

Если это так, то у вас есть пара вариантов.Вероятно, проще всего было бы «перехватить» поток вывода консоли с помощью составного TextWriter:

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()

если у вас нет контроля над исходным кодом консольного приложения, которое вы хотите «ти», и консольное приложение не требует ввода в середине своего выполнения, тогда вы можете использовать именованный канал дляполучить выходные данные приложения и перенаправить его.

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);                        
        }
    }
 }

Это очень простой пример;Вы можете обеспечить больше взаимодействия, используя двусторонний канал, но это потребует немного больше кода с вашей стороны.

0 голосов
/ 05 апреля 2013

Проработка ответа KeithS, это рабочая реализация. Он должен работать для всех вызовов Write / WriteLine без необходимости переопределять каждую перегрузку, потому что текущая (4.0, и я предполагаю ранее) реализация TextWriter направляет все записи через 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);
    }
}
0 голосов
/ 11 октября 2011

Я не собираюсь писать конкретные примеры кода, но я скажу вам, что вы можете посмотреть на каркасы журналирования, такие как log4net, в котором есть консоль и файловые аппендеры, которые будут делать то, что вы хотите.Вы не можете ошибиться в выражениях журнала в своем коде. Log.Debug («какое-то сообщение») настроить конфигурацию log4net на использование любого количества добавляемых вами устройств и заставить его записать сообщение сразу во все источники, например, screen, file,db, и отправлю вам электронное письмо одновременно.

Кажется, я пропустил последнее предложение вопроса о том, как заставить его работать с Tee, поэтому мой ответ может быть неверным.

0 голосов
/ 11 октября 2011

Вы можете попробовать следующее:

C:\you_csharp_program.exe arg1 arg2 arg3 |tee filename
...